Click here to Skip to main content
15,884,177 members
Articles / Programming Languages / Java
Tip/Trick

Be Careful with Virtual Method Calls from the Constructor (and Destructor) of your Classes in C++/C#/Java!

Rate me:
Please Sign up or sign in to vote.
4.67/5 (12 votes)
24 Aug 2013CPOL11 min read 84.1K   27   14
Avoid accidental virtual method calls in C++ constructors/destructors, Java constructors and be careful with them in C#!

Why?

Performing a virtual method call in a Base class constructor/destructor as a result of creating/deleting a Derived class instance carries a lot of danger depending on the language you are using if the Derived class overrides the specified virtual method and this can result in hard-to-find bugs. This rule holds for indirect virtual method calls too when your Base constructor or destructor calls a non-virtual or static method or a global function that somehow calls a virtual method of the object being constructed or destructed. There are some sharp differences between C++, C# and Java regarding the behavior and dangers of the previously described virtual method call.

Examination of these Dangerous Method Calls

The Order of Constructor/Destructor Calls in a Class Hierarchy

For demonstration, I will use the following class hierarchies:

Constructor call order is the following in case of constructing a Derived2 instance (for all 3 languages):

  1. Base
  2. Derived1
  3. Derived2

Destructor call order in case of C++ is the reverse of constructor call order:

  1. ~Derived2
  2. ~Derived1
  3. ~Base

The construction of an instance always starts with allocating/reserving a memory block for it before calling the constructor of the class being instantiated.

The "pseudo code" of the Constructors (Language Dependent)

The compiler of these languages may optionally put some auto generated code to the beginning and the end of your constructor/destructor code. It is up to the compiler how to generate code that works by following the rules of the language. I've provided some pseudo code that can be one possible implementation in a compiler for each language.

C#

C#
constructor()
{
    auto generated: initialize the member variables (fields) of this class
    auto generated: call the base class constructor (if we have a base class)
    [your constructor code here]
}

Java

Java
constructor()
{
    auto generated: call the base class constructor (if we have a base class)
    auto generated: initialize the member variables (fields) of this class
    [your constructor code here]
}

C++

C++
constructor()
{
    auto generated: call the base class constructor (if we have a base class)
    auto generated: initialize the table pointer to the vtable of this class
    [your constructor code here]
}

destructor()
{
    auto generated: initialize the vtable pointer to the vtable of this class
    [your destructor code here]
    auto generated: call the base class destructor (if we have a base class)
} 

Dangers as the Result of Different Constructor/Destructor Code in these Languages

C#

If you call a virtual method from a Base class constructor and the virtual method is overridden by the Derived class, then the given virtual method of the Derived class is executed before the Derived constructor call but fortunately all Derived member variables (fields) are already initialized. If you check out the pseudo code of a C# constructor, you can clearly see that a piece of auto-generated code in the Derived constructor initializes its own fields before calling the Base constructor. For this reason, every field (including the "most Derived" and Base class fields) of a C# instance are initialized before the execution of any constructors.

Thanks to Trojan McGill for pointing out the huge difference between C# and Java field initialization. (Basically, the difference between the pseudo code of C# and Java constructors.)

Java

In case of Java every class and base class member variables (fields) are initialized to their default value (nil, zero, ...). This initialization is followed by calling the constructor of the class being instantiated. If you perform a virtual method call in a Base constructor and the virtual method is overridden by the Derived class, then the given override of the Derived class is executed before the Derived constructor call (like in case of C#) and before the initialization of any Derived class member variables (this is different from C#!) so the Derived class member variables still hold their zero initialized default value at the time of this method call. This is the direct consequence of the structure of the auto generated code in the pseudo code of Java constructors above. In C#, such a virtual call can at least rely on the value of Derived member variables but in case of Java such a Derived virtual method call from a Base constructor finds just zero initialized member variables and nothing useful. This extremely lowers the value and usefulness of such a virtual method call from a Base class constructor and makes it very dangerous because an unintentional (usually indirect) virtual method call can cause very hard to find bugs!

C++

In C++, if you check out the pseudo code of the constructor and destructor, you will see that before the execution of your constructor body and destructor body the vtable is replaced to the vtable of the class whose constructor is being executed. This means that even if this object is the instance of a Derived class the dynamic type info along with the virtual method table is demoted only to that of the Base class for the duration of Base class constructor/destructor execution. As a result, if you call a virtual method from a Base class constructor/destructor then the Base class implementation is called even if a Derived class (of the instance being constructed) would have an override for that virtual method. Why? This behavior is defined by the language itself. An instance is built up progressing from the Base to Derived so while the Base part of an instance is being constructed it would be useless to call Derived virtual methods that have access to Derived member variables that are totally uninitialized in case of C++ before the execution of the Derived constructor. Gaining access to garbage and dangling pointers wouldn't be useful.

Impact on Software Design

The level of danger in case of these languages

My observation is that in case of C++ and Java such a virtual method call from a Base class constructor into the virtual method of an uninitialized Derived class is usually unintentional and is usually a bug. In case of C++ the worst case is a crash with "Pure virtual function call" runtime error! (You can find code below demonstrating this!) Unfortunately in case of complex constructors, it's very easy to put together a buggy solution in which a Derived virtual method either directly or indirectly (through several non-virtual or sealed/final methods) gets called. This is often the result of collaboration: Bob writes a non-virtual method that calls a virtual method, few days later Alice calls this non-virtual method from a base class constructor and forgets to check for a possible unwanted (protected/public) virtual call...

In C#, this problem has been clearly addressed by the designers of the language (by initializing the fields before calling any constructors) so such a virtual method call can be usable but is still dangerous if we consider that it is performed in the Derived class before the Derived constructor. If the Derived virtual method relies on the initializer code of the Derived constructor and the Base class constructor calls this virtual method unintentionally (possible through indirection) then it will case hard to find bug just like in case of C++ and Java!

Comparing the member variable (field) initialization of C# and Java: the designers of C# sacrificed some degree of flexibility when it comes to the initializer code of C# class member variables. In Java, you can use the instance member variables and methods (and inner non-static classes) flexibly when it comes to initializing the class member variables but as you will see later in the examples this flexibility carries a lot of danger that is related to the dangerous virtual method calls we were talking about.

Recommendations to help avoiding bugs

In case of all 3 languages, I advise you to track down the list of method that are called from the constructor directly or indirectly.

C++

In C++, it is (usually) a bug if you call any virtual methods directly or indirectly from constructors. My observation is that most C++ programmers are unaware of the strange behavior and for some reason, they expect the Derived virtual method to be called without being unaware of the fact that a virtual Derived method call would have access only to uninitialized garbage. In most cases, the virtual method is called indirectly by calling only an innocent non-virtual method from the constructor...

Java

Like in case of C++, a virtual method call directly or indirectly is most likely to be a bug in Java. As you will see in an example below there are a dozen ways to call a virtual method from your constructor "accidentally" while there are only a few valid reasons to call a virtual method from a Base class constructor. In Java, if you call the virtual method of a Derived class from a Base constructor you can use only constants and static member variables and methods and maybe some external sources to perform calculations to return something useful. Such a functionality is rarely needed. For this reason, I highly recommend you to check out the list of directly/indirectly called methods and make sure that you either call private or final methods (that cannot be overridden by Derived classes) or in case of calling public/protected methods I've seen somewhere a recommendation to mark such public/protected (and sometimes default) methods with the final keyword to prevent Derived classes from overriding it.

C#

In C#, the chance of ending up with malfunctioning code as a result of calling a virtual method from a Base constructor is much smaller than in case of Java and C++. Still, if your Base class is not for internal use in your library but is public for others so as to Derive their own classes from it then you have to be careful because calling a virtual method from your Base class constructor can have a huge impact on the functioning of the code built on top of your library. In case of such Base classes that serve as public interfaces, I would avoid calling public/protected virtual methods if they aren't reasonable. By calling a protected/public virtual method from your constructor you potentially make your Base class constructor code dependent on the contents of the constructor of a class someone else Derives from your Base.

Case study

Just came to my mind that I've recently eliminated a nasty virtual call from a Base class constructor in a C++ GUI library. At program startup, some GUI elements misbehaved for some period of time and after some usage some of these GUI elements started to behave correctly. The problem was that the Base class, the "mother" of all GUI controls (CGuiControl) had a constructor overload that allowed one to specify the parent control while creating the control. The constructor that allowed setting the parent contained the following piece of code at the end of the constructor body:

C++
if (parent)
    SetParent(parent);  

The problem with this is that SetParent is a virtual method call that has been overwritten by several specialized controls. If we call it from a Base class constructor, then only the Base class implementation is called without allowing the Derived classes to take special action. To make things worse, the Base class implementation of SetParent calls a lot of other methods (that perform for example layout management) and there were some virtual methods among these methods too!

So the library provided two different ways to create a GUI control by placing it on a parent control (in the GUI control hierarchy):

  1. Creating the control with the constructor that optionally sets the parent.
  2. Creating the control with another constructor and then calling SetParent() on the fully constructed control.

From these two possible methods, I simply eliminated the first option by forcing everyone to set the parent only after construction of the control. With this, I moved out some complex initialization from the constructor and eliminated an ugly bug!

Conclusion

Calling a lot of methods (performing complex initialization) in your constructor increases the chance of calling a virtual method indirectly. In case of C++, I find it a good practice to do just basic member variable initialization whenever possible. Even in case of Java, it worth checking out for possible virtual method calls caused by method calls from your constructor or from the auto-generated part of your constructor that initializes the member variables! In case of C#, chances are less to put in a dangerous bug but be careful when you design the interface of a library between programmers and teams!

Example Code Pieces to Check Out this Behavior

In case of C# and Java, we are speaking only about the constructor as finalizes are not really used.

C#

Test.cs:

C#
using System;

namespace Test
{
    public class Base
    {
        public Base()
        {
            System.Console.WriteLine("Base.Base");
            ABitDangerousCall();
        }

        public virtual void ABitDangerousCall()
        {
            System.Console.WriteLine("Base.ABitDangerousCall");
        }

        private class Inner
        {
            public Inner()
            {
                System.Console.WriteLine("Base.Inner.Inner");
            }
        }
        private Inner inner = new Inner();
    }

    class Derived : Base
    {
        public Derived()
        {
            System.Console.WriteLine("Derived.Derived");
            ctorInitializedMember = 5;
        }

        // ctorInitializedMember is default initialized to zero before the constructor initializes it.
        private int ctorInitializedMember;
        private int derivedInt = 6;

        public override void ABitDangerousCall()
        {
            System.Console.WriteLine(String.Format("Derived.ABitDangerousCall 
            ctorInitializedMember={0} derivedInt={1}", ctorInitializedMember, derivedInt));
        }

        private class Inner
        {
            public Inner()
            {
                System.Console.WriteLine("Derived.Inner.Inner");
            }
        }
        private Inner inner = new Inner();
    }

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

The output of the above program:

Derived.Inner.Inner
Base.Inner.Inner
Base.Base
Derived.ABitDangerousCall ctorInitializedMember=0 derivedInt=6
Derived.Derived 

The Derived.Inner.Inner and the Base.Inner.Inner class prove that the field initializations happen before the execution of any constructors. The base class constructor calls Derived.ABitDangerousCall before the Derived constructor so both the ctorInitializedMember and the derivedInt has been default initialized, the Derived constructor hasn't yet been initialized the ctorInitializedMember to 5.

Java

Test.java:

Java
class Base
{
    public Base()
    {
        System.out.println("Base.Base");
        DangerousCall();
    }
    
    public void DangerousCall()
    {
        System.out.println("Base.DangerousCall");
    }
}

class Derived extends Base
{
    public Derived()
    {
        System.out.println("Derived.Derived");
    }
    
    @Override
    public void DangerousCall()
    {
        System.out.println("Derived.DangerousCall");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        new Derived();
    }
}  

The output of the above program:

Base.Base
Derived.DangerousCall
Derived.Derived

This means that the Base class constructor was able to call the DangerousCall method of the Derived class before the execution of the Derived constructor!!! Programmers usually expect a constructor to be executed as the very first "method" of any class!!!

Here is a more complicated example that shows the ease of putting some hidden virtual method calls into your constructor:

Test.java:

Java
import java.util.ArrayList;
import java.util.List;

class Base
{
    public Base()
    {
        System.out.printf("Base.Base intVar=%s\n", intVar);
        DangerousCall();
    }

    // This initialization is copied to the beginning of every constructor as auto-generated code.
    private int intVar = virtualCallFromConstructor();

    private class NonStaticInnerClass
    {
        // This initialization is copied to the beginning of every constructor as auto-generated code.
        // Since an instance of this is created from the constructor of Base we are able to call
        // the virtual methods of Base so we can call an overridden method in Derived before the
        // Derived constructor!
        int innerClassInt = virtualCallFromConstructor();

        NonStaticInnerClass()
        {
            System.out.printf(
              "NonStaticInnerClass.NonStaticInnerClass innerClassInt=%s\n", 
              innerClassInt);
        }
    }

    // This initialization is copied to the beginning
    // of every constructor as auto-generated code.
    private NonStaticInnerClass innerClassInstance = new NonStaticInnerClass();

    private List<Integer> baseIntList;

    // These initializer blocks may contain arbitrary
    // code and they are copied to the beginning of
    // every constructor as auto-generated code.
    // It's very easy to put in some virtual method calls!!!
    {
        baseIntList = new ArrayList<Integer>();
    }

    protected int virtualCallFromConstructor()
    {
        System.out.println("Base.virtualCallFromConstructor");
        return 5;
    }

    public void DangerousCall()
    {
        System.out.println("Base.DangerousCall");
    }
}

class Derived extends Base
{
    public Derived()
    {
        System.out.println("Derived.Derived");
    }

    // This initialization is copied to the beginning
    // of every constructor as auto-generated code.
    private int derivedIntVar = 6;

    @Override
    protected int virtualCallFromConstructor()
    {
        System.out.printf(
          "Derived.virtualCallFromConstructor derivedIntVar=%s\n", derivedIntVar);
        // If this method is called before the constructor then derivedIntVar contains
        // its zero initialized default value: zero.
        return derivedIntVar;
    }

    // This initialization is copied to the beginning of every constructor as auto-generated code.
    private List<Integer> intList = new ArrayList<Integer>();

    @Override
    public void DangerousCall()
    {
        // If this method is called before the constructor then intList and derivedIntVar contain
        // their zero initialized default values: nil and zero.
        System.out.printf("Derived.DangerousCall intList=%s derivedIntVar=%s\n", 
                          intList, derivedIntVar);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        new Derived();
    }
}

The output of the above program:

Derived.virtualCallFromConstructor derivedIntVar=0
Derived.virtualCallFromConstructor derivedIntVar=0
NonStaticInnerClass.NonStaticInnerClass innerClassInt=0
Base.Base intVar=0
Derived.DangerousCall intList=null derivedIntVar=0
Derived.Derived

The first line was printed as a result of initializing Base.intVar. The second line was printed as a result of initializing Base.NonStaticInnerClass.innerClassInt. Zero int values everywhere and intList==null in our Derived.DangerousCall???

C++

Test.cpp:

C++
#include <stdio.h>

class Base
{
public:
    Base()
    {
        printf("Base.Base\n");
        DangerousCall();
    }

    ~Base()
    {
        printf("Base.~Base\n");
        DangerousCall2();
    }

    virtual void DangerousCall()
    {
        printf("Base.DangerousCall\n");
    }

    virtual void DangerousCall2()
    {
        printf("Base.DangerousCall2\n");
    }
};

class Derived : public Base
{
public:
    Derived()
    {
        printf("Derived.Derived\n");
    }

    ~Derived()
    {
        printf("Derived.~Derived\n");
    }

    virtual void DangerousCall()
    {
        printf("Derived.DangerousCall\n");
    }


    virtual void DangerousCall2()
    {
        printf("Derived.DangerousCall2\n");
    }
};

int main()
{
    Derived d;
    return 0;
}

The output of the above program:

Base.Base
Base.DangerousCall
Derived.Derived
Derived.~Derived
Base.~Base
Base.DangerousCall2

The Base constructor was unable to call the Derived.DangerousCall override before the execution of the Derived constructor. Similarly, the Base destructor was unable to call the Derived.DangerousCall2 override after the Derived destructor.

An indirect abstract (pure virtual) method call from your constructor or destructor can cause an immediate runtime error crash with an error message that usually and surprisingly contains "pure virtual method call" as the reason. BTW, have you ever wondered why does the CRT in the generated executable contains this "pure virtual method call" error message??? :-) :-) :-)

Example code that demonstrates a "pure virtual method call" runtime error:

C++
#include <stdio.h>

class Base
{
public:
    Base()
    {
        printf("Base.Base\n");
        // Any decent compiler would find out that calling an abstract (pure virtual)
        // method directly from a constructor is an error.
        Indirection();
    }

    ~Base()
    {
        printf("Base.~Base\n");
        // Any decent compiler would find out that calling an abstract (pure virtual)
        // method directly from a destructor is an error.
        Indirection();
    }

    void Indirection()
    {
        // Here the compiler silently assumes that the vtable is initialized to that
        // of an instantiated class (that can't have an abstract (pure virtual) method
        // but this isn't always true during object construction and destruction!
        // If you call Indirection() from the constructor or destructor then the vtable
        // of Base will contain to an auto-generated implementation of the
        // DangerousCall method that crashes with a runtime error!
        DangerousCall();
    }

    virtual void DangerousCall() = 0;
};

class Derived : public Base
{
public:
    Derived()
    {
        printf("Derived.Derived\n");
    }

    ~Derived()
    {
        printf("Derived.~Derived\n");
    }

    virtual void DangerousCall()
    {
        printf("Derived.DangerousCall\n");
    }
};

int main()
{
    Derived d;
    return 0;
}  

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIs this still working? Pin
Maximilien23-Jan-15 3:42
Maximilien23-Jan-15 3:42 
AnswerRe: Is this still working? Pin
pasztorpisti23-Jan-15 11:01
pasztorpisti23-Jan-15 11:01 
QuestionMy vote of 5 Pin
kanalbrummer4-Sep-14 2:06
kanalbrummer4-Sep-14 2:06 
Very good Explanation. Somehow I knew that I am not allowed to call virtual functions from within a constructor or a destructor. Then your article gave me the detailed information I needed. Thanks!
QuestionWhat about abstract method/class Pin
Carlos190711-Jun-14 13:54
professionalCarlos190711-Jun-14 13:54 
AnswerRe: What about abstract method/class Pin
pasztorpisti11-Jun-14 21:33
pasztorpisti11-Jun-14 21:33 
GeneralRe: What about abstract method/class Pin
Carlos190712-Jun-14 0:50
professionalCarlos190712-Jun-14 0:50 
GeneralRe: What about abstract method/class Pin
pasztorpisti12-Jun-14 1:35
pasztorpisti12-Jun-14 1:35 
GeneralRe: What about abstract method/class Pin
Carlos190712-Jun-14 1:51
professionalCarlos190712-Jun-14 1:51 
GeneralGreat technical article, my 5 Pin
H.Brydon25-Aug-13 16:34
professionalH.Brydon25-Aug-13 16:34 
QuestionC++ vs C++/CLI Pin
Philippe Mori22-Aug-13 6:46
Philippe Mori22-Aug-13 6:46 
AnswerRe: C++ vs C++/CLI Pin
pasztorpisti22-Aug-13 7:56
pasztorpisti22-Aug-13 7:56 
GeneralMy vote of 3 PinPopular
Trajan McGill22-Aug-13 6:23
Trajan McGill22-Aug-13 6:23 
GeneralRe: My vote of 3 Pin
pasztorpisti22-Aug-13 8:47
pasztorpisti22-Aug-13 8:47 
GeneralRe: My vote of 3 Pin
Trajan McGill22-Aug-13 10:01
Trajan McGill22-Aug-13 10:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.