Virtual method calls from constructors


C++ and C# varies considerably in how virtual method calls from constructors work. I feel that the approach taken by C++ is significantly better. Let’s consider the following code in C++.

#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
Foo();
}
virtual void Foo()
{
cout << “Base::Foo” << endl;
}
};

class Derived : Base
{
public:
Derived()
{
}
void Foo()
{
cout << “Derived::Foo” << endl;
}
};
Derived* der = new Derived();


The output of the program is Base::Foo.


Here the Base class constructor is calling the virtual method Foo. In C++  (as with most OO language) the Base class is created before the Derived class and hence the base class constructor is called first. So when the call to Foo is made in Base::Base(), Derived is not yet created and hence the call Foo() ends in Base::Foo and not its override in Derived::Foo.


In C# the behavior is different and always the most derived override is called.

class Base
{
public Base()
{
Foo();
}

public virtual void Foo()
{
Console.WriteLine(“Base::Foo”);
}
}

class Derived : Base
{
string str = null;
public Derived()
{
str = “Hello world”;
}

public override void Foo()
{
Console.WriteLine(“Derived::Foo”);
//Console.WriteLine(str);
}
}

class Program
{
static void Main(string[] args)
{
Derived der = new Derived();
}
}


In this case the output is Derived::Foo. Even in C# the base class is created first and its constructor is called first. However calls to virtual methods always land on the most derived version which in this case is Derived::Foo().


However there are issues with this. Even though Derived::Foo gets called, Derived class is still not initialized properly and its constructor is not yet called. In the above code the variable str is not initialized and if it is referred from Derived::Foo a null reference will occur. So I tend to believe that even though C++ implementation needs a bit more understanding of object creation (vtable build-up) it is safer.


Due to all these subtleties its always recommended to not refer to virtual methods from ctors. If for example you are writing some code that will be used by others (as in Frameworks) then this may break the client developers if they derive from your class. They may never anticipate that calls to their overrides may hit un-initialized variables which they have explicitly initialized in the derived class’s constructor.

Comments (10)

  1. Anonymous says:

    "However there are issues with this. Even though Derived::Foo gets called, Derived class is still not initialized properly and its constructor is not yet called. "

    Could that not also be argued the other way around? If you call the derived constructor first, then you might end up accessing somethng from the base class that’s not yet initialized there.

    Also I wonder if this behaviour might be related to what you’d expect for:

    public class Derived : Base

    {

      public Derived(string s) : base(s)

      {

         //…

      }

      //…

    }

    where you kind of ‘explicitly’ say that you want the base constructor to be called first. Or am I way off on that one 🙂

  2. You can should never have derived getting initialized before the base 🙂 It’d be like building the rooms before the foundation of a house.

    I said C++ implementation to be better because virtual function calls lands up on the inheritance level which has been initialized…

  3. Anonymous says:

    "You can should never have derived getting initialized before the base 🙂 It’d be like building the rooms before the foundation of a house."

    Yeah that was the point I was trying to make hehe.

    "I said C++ implementation to be better because virtual function calls lands up on the inheritance level which has been initialized…"

    Aha! Count on me to misinterpret the point of your post :p

  4. Anonymous says:

    One of the blogs i’ve been reading a lot lately is I know the answer (it’s 42). I’ve added it to my Reader…

  5. Anonymous says:

    Absolutely correct.  No virtual function calls should be placed in the constructor and if the programmer does place a virtual method call in the constructor the compiler should do something sensible as done by the C++ compiler (i.e treat the call as a normal function call and not using virtual call mechanism) or better still give a compiler warning or an error so that the programmer realises his mistake immediately.  C# compiler does neither.  Of course this is not the only point of contention I have against C#.

  6. Anonymous says:

    "i.e treat the call as a normal function call and not using virtual call mechanism"

    No, it uses the mechanism (which is "call the final overrider according to the dynamic type of the object"), but the result of the application is the base class because dynamic type in constructor and destructor is the base.

    Just imagine that we don’t call the vf directly from the ctor, but call another function g which contains this vf call. the function g can be called from anywhere and anytime, not only during construction/destruction, so it’s obvious that implementation of g will have virtual call off Foo and anyway will work corerctly (result Base::Foo in case of call from ctor/dtor, but Derived::Foo in other cases).

    But when vf is called directly from ctor/dtor, of course the compiler can optimize the call and call Base::Foo directly without using virtual call mechanism.

  7. Anonymous says:

    The way C# handles virtual method calls from constructors has both pros and cons. The cons are mentioned above. One pro that I see is that it allows us to call a factory method from constructor, which would be impossible with C++.

    Suppose that the Base class has a private member of type MyBaseControl, which is created in the Base constructor. Let’s say methods of Base class access that MyBaseControl object for their purposes. Now suppose that I derive MyDerivedControl from MyBaseControl, and moreover, I want the Derived class to work with MyDerivedControl instead of MyBaseControl. This can be accomplished by extracting the code that creates MyBaseControl object into a virtual function (factory method pattern) that returns the created instance. Base constructor will call the factory method instead of creating instance of hard-coded type directly. The Derived class can override that factory method to create and return instance of MyDerivedControl instead.

    Now regarding initialization of derived class, we can initialize some members directly in their declaration, and those members will be initialized before the call to the base constructor. Therefore, there will be no problem by the time an overridden method will be called from the base constructor.

  8. Anonymous says:

    I’m with Felix on this one.  Touching undefined variables is a problem, but being able to use factory methods in the constructor is very useful.  

  9. David says:

    Actually the problem really is that C++ classes are not themselves objects (one of the reasons C++ can’t really be called an OO language) and so you can’t pass classes around as parameters (NB, I’m not talking about template hacks, that’s a whole different can of worms).

    If you look at a language like Delphi (object Pascal) which allows constructors to be virtual (and classes can be passed around as parameters), then there are tremendous benefits to virtual constructors.

    So it’s not that the approach in C++ is better, it’s just that you can’t DO it properly in C++

  10. Rune says:

    There's an easy way around the null ref in your C# code. Simply use an initializer instead of initializing in the constructors. Initializers are called in reverse order of the constructors. So in the end the C# approach is more flexible than the c++