Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it safe to call a virtual function in a constructor

I have some code where I really want to call a virtual method from a constructor. I know this is considered unsafe, and I know enough about object construction to also understand why. I also am not experiencing these problems. Currently my code is working and I think it should be fine, but I want to make sure.

Here is what I am doing:

I have some class hierarchy and there is a normal public function which just forwards to a private virtual method, as usual. However I do want to call this public method upon construction of my objects, because it is filling all data into the object. I will be absolutely sure that this virtual call comes from the leaf class, because using this virtual method from any other part of the class hierarchy simply does not make sense at all.

So in my opinion the object creation should be finished once I am doing the virtual call and everything should be fine. Is there still anything that could go wrong? I guess I'll have to mark this part of the logic with some big comments to explain why this logic should never ever be moved to any of the base clases, even though it looks like it could be moved. But other than stupidity of other programmers I should be fine, shouldn't I?

like image 553
LiKao Avatar asked Dec 28 '22 07:12

LiKao


1 Answers

It is absolutely safe to call any non-abstract virtual function in the constructor or the destructor! However, its behavior may be confusing as it may not do what is expected. While the constructor of a class is executed, the static and dynamic type of the object is the type of the constructor. That is, the virtual function will never be dispatched to the override of a further derived class. Other than that, virtual dispatch actually works: e.g. when calling a virtual function via a base class pointer or reference correctly dispatches to the override in the class being currently constructor or destructed. For example (probably riddled with typos as I currently can't this code):

#include <iostream>
struct A {
    virtual ~A() {}
    virtual void f() { std::cout << "A::f()\n"; }
    void g() { this->f(); }
};
struct B: A {
    B() { this->g(); } // this prints 'B::f()'
    void f() { std::cout << "B::f()\n"; }
};
struct C: B {
    void f() { std::cout << "C::f()\n"; } // not called from B::B()
};

int main() {
    C c;
}

That is, you can call a virtual function, directly or indirectly, in the constructor or a destructor of a class if you don't want the virtual function to be dispatched to a further derived function. You can even do this is virtual function is abstract in the given class as long as it is defined. However, having an undefined abstract function being dispatched to will cause a run-time error.

like image 190
Dietmar Kühl Avatar answered Feb 28 '23 17:02

Dietmar Kühl