Jaa


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

  • Anonymous
    February 27, 2006
    The comment has been removed
  • Anonymous
    February 28, 2006
    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...
  • Anonymous
    February 28, 2006
    "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
  • Anonymous
    March 02, 2006
    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...
  • Anonymous
    May 08, 2006
    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#.
  • Anonymous
    May 17, 2006
    The comment has been removed
  • Anonymous
    August 14, 2006
    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.
  • Anonymous
    January 25, 2007
    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.  
  • Anonymous
    July 27, 2009
    The comment has been removed
  • Anonymous
    June 14, 2011
    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++