Calling Virtual Method in Base Class Constructor

Calling virtual functions inside constructors

Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.

The C++ FAQ Lite covers this in section 23.7 in pretty good detail. I suggest reading that (and the rest of the FAQ) for a followup.

Excerpt:

[...] In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn’t yet happened. Objects are constructed from the base up, “base before derived”.

[...]

Destruction is done “derived class before base class”, so virtual functions behave as in constructors: Only the local definitions are used – and no calls are made to overriding functions to avoid touching the (now destroyed) derived class part of the object.

EDIT Corrected Most to All (thanks litb)

Calling virtual method in base class constructor

(This answer applies to C# and Java. I believe C++ works differently on this matter.)

Calling a virtual method in a constructor is indeed dangerous, but sometimes it can end up with the cleanest code.

I would try to avoid it where possible, but without bending the design hugely. (For instance, the "initialize later" option prohibits immutability.) If you do use a virtual method in the constructor, document it very strongly. So long as everyone involved is aware of what it's doing, it shouldn't cause too many problems. I would try to limit the visibility though, as you've done in your first example.

EDIT: One thing which is important here is that there's a difference between C# and Java in order of initialization. If you have a class such as:

public class Child : Parent
{
private int foo = 10;

protected override void ShowFoo()
{
Console.WriteLine(foo);
}
}

where the Parent constructor calls ShowFoo, in C# it will display 10. The equivalent program in Java would display 0.

Is it bad practice to call a virtual function from constructor of a class that is marked final

Regarding

Normally calling virtual functions from constructors is considered bad practice, because overridden functions in sub-objects will not be called as the objects have not been constructed yet.

That is not the case. Among competent C++ programmers it’s normally not regarded as bad practice to call virtual functions (except pure virtual ones) from constructors, because C++ is designed to handle that well. In contrast to languages like Java and C#, where it might result in a call to a method on an as yet uninitialized derived class sub-object.

Note that the dynamic adjustment of dynamic type has a runtime cost.

In a language oriented towards ultimate efficiency, with "you don't pay for what you don't use" as a main guiding principle, that means that it's an important and very much intentional feature, not an arbitrary choice. It's there for one purpose only. Namely to support those calls.


Regarding

In this case class derived is marked as final so no o further sub-objects can exist. Ergo the virtual call will resolve correctly (to the most derived type).

The C++ standard guarantees that at the time of construction execution for a class T, the dynamic type is T.

Thus there was no problem about resolving to incorrect type, in the first place.


Regarding

Is it still considered bad practice?

It is indeed bad practice to declare a member function virtual in a final class, because that’s meaningless. The “still” is not very meaningful either.

Sorry, I didn't see that the virtual member function was inherited as such.

Best practice for marking a member function as an override or implementation of pure virtual, is to use the keyword override, not to mark it as virtual.

Thus:

void startFSM() override
{ theFSM_.start(); }

This ensures a compilation error if it is not an override/implementation.

How to call derived class virtual method from base class constructor?

I think:

No reason C++ can not do java/C# virtual contructor mechanism.

I want to break the C++ rules.

I also hope that C++ can write less to do more.

Would not progress if C++ does not improve, so that more people can not easily entry.

class MyClass1
{
public:
MyClass1()
{
init();
}

typedef void (MyClass1::virtual_init)();
MyClass1(virtual_init vinit)
{
(this->*vinit)();
}

//virtual void init()
void init()
{
printf("MyClass1 init");
}
}

class MyClass2 : public MyClass1
{
public:
MyClass2()
: MyClass1(&MyClass2::init)
{
}

//virtual void init()
void init()
{
printf("MyClass2 init");
}
}

Virtual member call in a constructor

When an object written in C# is constructed, what happens is that the initializers run in order from the most derived class to the base class, and then constructors run in order from the base class to the most derived class (see Eric Lippert's blog for details as to why this is).

Also in .NET objects do not change type as they are constructed, but start out as the most derived type, with the method table being for the most derived type. This means that virtual method calls always run on the most derived type.

When you combine these two facts you are left with the problem that if you make a virtual method call in a constructor, and it is not the most derived type in its inheritance hierarchy, that it will be called on a class whose constructor has not been run, and therefore may not be in a suitable state to have that method called.

This problem is, of course, mitigated if you mark your class as sealed to ensure that it is the most derived type in the inheritance hierarchy - in which case it is perfectly safe to call the virtual method.

Calling a virtual function from the constructor

And I'm wondering if mine code is fine even if it breaks this rule:

It depends on what you mean by "fine". Your program is well-formed, and its behavior is well-defined, so it won't invoke undefined behavior and stuff like that.

However, one may expect, when seeing a call to a virtual function, that the call is resolved by invoking the implementation provided by the most derived type which overrides that function.

Except that during construction, the corresponding sub-object has not been constructed yet, so the most derived subobject is the one currently being constructed. Result: the call is dispatched as if the function were not virtual.

This is counter-intuitive, and your program should not rely on this behavior. Therefore, as a literate programmer, you should get used to avoid such a pattern and follow Scott Meyer's guideline.

Calling virtual function of derived class from base class constructor?

Even though it's a virtual function, the base's version will get called since the derived class isn't fully constructed yet. The base class constructor is called before the derived class constructor, so if the derived virtual function were to get called, it would be with an incompletely-initialized instance - a possible (probably) recipe for disaster.

call to pure virtual function from base class constructor

There are many articles that explain why you should never call virtual functions in constructor and destructor in C++. Take a look here and here for details what happens behind the scene during such calls.

In short, objects are constructed from the base up to the derived. So when you try to call a virtual function from the base class constructor, overriding from derived classes hasn't yet happened because the derived constructors haven't been called yet.

Calling pure virtual function in constructor gives an error

Calling virtual functions in a constructor is recognised as a bad thing to do.

During base class construction of a derived class object, the type of
the object is that of the base class. Not only do virtual functions
resolve to the base class, but the parts of the language using runtime
type information (e.g., dynamic_cast (see Item 27) and typeid) treat
the object as a base class type.

So your instantiation of b invokes the a constructor. That calls foo(), but it's the foo() on a that gets called. And that (of course) is undefined.



Related Topics



Leave a reply



Submit