Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual Function During Construction Workaround

I've got a base class that has a virtual function. I want to call that class during the construction because I want the function called for each of the derived classes. I know I can't call a virtual function during construction, but I can't think of an elegant (i.e., avoid repeating code) solution.

What are some work arounds to calling a virtual function during construction?

The reason I want to avoid this is because I don't want to have to create constructors that just call the base class.

class A {
    public:
        A() {
            read();
        }

        // This never needs to be called
        virtual void read() = 0;
}

class B:A {
    public:
        B():A() {   };
        read() { /*Do something special for B here.*/ }

}

class C:A {
    public:
        C():A() {   };
        read() { /*Do something special for C here.*/ }

}

PS: The Python way of doing this is simply to raise NotImplementedError in A::read(). I'm returning to C++ and I'm more rusty than I thought.

like image 626
jlconlin Avatar asked Dec 20 '25 12:12

jlconlin


1 Answers

The FAQ perspective.

This is a Frequently Asked Question.

See the C++ FAQ item titled “Okay, but is there a way to simulate that behavior as if dynamic binding worked on the this object within my base class's constructor?”.

It’s very often a good idea to check the FAQ (and generally, googling or altavista’ing) before asking.


The question as “Derived class specific base initialization”.

To be clear, while the literal question above is

“What are some work arounds to calling a virtual function during construction?”

it is evident that what’s meant is

“How can a base class B be designed so that each derived class can specify part of what goes on during B construction?”

A major example is where C style GUI functionality is wrapped by C++ classes. Then a general Widget constructor might need to instantiate an API-level widget which, depending on the most derived class, should be a button widget or a listbox widget or whatever. So the most derived class must somehow influence what goes on up in Widget’s constructor.

In other words, we’re talking about derived class specific base construction.

Marshall Cline called that “Dynamic Binding During Construction”, and it’s problematic in C++ because in C++ the dynamic type of an object during class T construction and destruction, is T. This helps with type safety, in that a virtual member function is not called on a derived class sub-object before that sub-object has been initialized, or its initialization has started. But a major cost is that DBDI (apparently) can’t be done in a way that is both simple and safe.


Where the derived class specific init can be performed.

In the question the derived class specific action is called read. Here I call it derived_action. There are 3 main possibilities for where the derived_action is invoked:

  • Invoked by instantiation code, called two-phase construction.
    This essentially implies the possibility of having a mostly unusuable not fully initialized object at hand, a zombie object. However, with C++11 move semantics that has become more common and accepted (and anyway it can be mitigated to some extent by using factories). A main problem is that during the second phase of construction the ordinary C++ protection against virtual calls on uninitialized sub-objects, due to dynamic type changes during construction, is not present.

  • Invoked by Derived constructor.
    For example, derived_action can be invoked as an argument expression for the Base constructor. A not totally uncommon technique is to use a class template to generate most derived classes that e.g. supply calls of derived_action.

  • Invoked by Base constructor.
    This implies that knowledge of derived_action must be passed up to the constructor, dynamically or statically. A nice way is to use a defaulted constructor argument. This leads to the notion of a parallel class hierarchy, a hierarchy of derived class actions.

This list is in order of increasing sophistication and type safety, and also, to the best of my knowledge, reflects the historical use of the various techniques.

E.g. in Microsoft’s MFC and Borland’s ObjectWindows GUI early 1990’ libraries two-phase construction was common, and that kind of design is now, as of 2014, regarded as very ungood.

like image 172
Cheers and hth. - Alf Avatar answered Dec 23 '25 00:12

Cheers and hth. - Alf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!