The Wind-Up Bird
The Wind-Up Bird

Reputation: 661

C++ Derived Classes - Calling a virtual function from the parent class?

I'm relatively new to writing large packages in C++, and as such am not totally familiar with some of the OOP techniques in the language.

I am working on a code that can run simulations to calculate the deformation of a material within the framework of various models. I have an overarching Sim class with methods such as set_boundary_conditions(), update_grid(), solve(), etc.

I would like to implement various models as derived classes. For example, I will have an ElasticSim class which derives from Sim if you would only like to consider the equations of linear elasticity, PlasticSim for plasticity, etc. etc.

Because the model defines the equations that must be solved, which comes into the update_grid() function, I have made update_grid() virtual so that it can be implemented differently for each model. Furthermore, set_boundary_conditions() is even more specific - different simulations within a given model will have different boundary conditions, so this should be virtual both in Sim and in any derived class. There will be another derived class which implements the boundary conditions for a given physical situation.

This may be overly complicated, but I think it is a very modular and versatile way to approach this problem. But I digress. I have one major question.

First, the solve() method is going to be identical for every model. Hence, I would like to define it in Sim. However, it calls virtual functions that will later be implemented by derived classes. Namely, in a bastardization of pseudocode and c++:

Sim::set_boundary_conditions()
for every time step...
    Sim::update_grid()

There will be quite a lot of coding before I can actually test this properly, and I have been unable to find a proper answer online. Does this actually make sense? In particular, I am calling Sim::update_grid() and Sim::set_boundary_conditions(), despite the fact that these functions will actually be implemented in a derived class and a derived class of a derived class respectively.

Upvotes: 1

Views: 630

Answers (1)

user4842163
user4842163

Reputation:

Does this actually make sense?

Yes, and that's perfectly fine for Sim::solve to be non-virtual and call virtual functions. Only cases where you have to watch out for virtual calls is in constructors and destructors (because the vtable may yet be fully formed or may already be destroyed).

An idiom that might be useful to you at some point is NVI (non-virtual interface). The idea consists of using non-virtual methods for public interfaces and virtual methods for protected/private methods. The idea is to allow central control but still allow overridability of certain parts. Example:

class Foo
{
public:
    virtual ~Foo() {}

    // public non-virtual interface: calls virtual interface.
    void do_something()
    {
        // Can add central stuff here that affects the 
        // entire hierarchy at any given time.
        do_something_impl();
    }

private:
    // subclasses can override this part.
    virtual void do_something_impl() = 0;
};

This kind of design leaves wiggle room to do something centrally applicable to the entire hierarchy (in foresight or in hindsight) while allowing subclasses to partially-override the behavior and lead to new sub-branches of code.

Yet what you have with this central sim method defined in your base class calling virtual methods is fine. That would make it into an abstract base class mixing concrete implementation and overridable interfaces rather than a pure virtual interface devoid of any concrete implementation, e.g. In the same sense, it's worth noting that you can provide default implementations for virtual functions -- not all methods in your base class need to be pure virtuals, or even virtual functions at all.

Upvotes: 2

Related Questions