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):
Base
Derived1
Derived2
Destructor call order in case of C++ is the reverse of constructor call order:
~Derived2
~Derived1
~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#
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
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++
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:
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):
- Creating the control with the constructor that optionally sets the parent.
- 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:
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;
}
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:
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:
import java.util.ArrayList;
import java.util.List;
class Base
{
public Base()
{
System.out.printf("Base.Base intVar=%s\n", intVar);
DangerousCall();
}
private int intVar = virtualCallFromConstructor();
private class NonStaticInnerClass
{
int innerClassInt = virtualCallFromConstructor();
NonStaticInnerClass()
{
System.out.printf(
"NonStaticInnerClass.NonStaticInnerClass innerClassInt=%s\n",
innerClassInt);
}
}
private NonStaticInnerClass innerClassInstance = new NonStaticInnerClass();
private List<Integer> baseIntList;
{
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");
}
private int derivedIntVar = 6;
@Override
protected int virtualCallFromConstructor()
{
System.out.printf(
"Derived.virtualCallFromConstructor derivedIntVar=%s\n", derivedIntVar);
return derivedIntVar;
}
private List<Integer> intList = new ArrayList<Integer>();
@Override
public void DangerousCall()
{
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:
#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:
#include <stdio.h>
class Base
{
public:
Base()
{
printf("Base.Base\n");
Indirection();
}
~Base()
{
printf("Base.~Base\n");
Indirection();
}
void Indirection()
{
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;
}