You are on page 1of 4

Object Creation and Handling

11. Avoid calling virtual functions in constructors.


Constructors do not support runtime polymorphism fully as the derived objects are not
constructed yet when base class constructor executes. So, avoid calling virtual functions from
base-class constructors, which might result in subtle bugs in the code.
When inheritance is involved, when a derived class object is constructed, the base class constructor is
called first and then the derived class constructors are called. Constructors are for initializing the object
– the base class constructor is responsible for initializing the base class part of the object, and derived
class constructors are responsible for initializing the derived class parts of the object.
Invoking virtual methods inside constructors is not the same as calling virtual methods from other
functions. Constructors are for initializing the object, for which the static type is known. Virtual
functions are invoked on the dynamic type of the object, but the object might not be properly initialized
while constructor call is made. Since the derived parts of the object wouldn’t be initialized while
executing the base class constructor, calling any virtual methods from the base class constructor doesn’t
work well. Depending on the language semantics different problems can happen, leading to subtle bugs
in the code (which is covered in detail with examples later in this tip).
How about the classes that aren’t inherited – is it acceptable to call virtual functions from the
constructors of those classes?
If the class is prevented from being inherited (for example, with private constructors or by declaring the
class as non-inheritable), then there is no problem as the class cannot serve as a base class in future.
The other possibility is that the class is inheritable and we make some virtual method calls in the
constructor; in future, if that class is inherited in future, and the virtual method called is overridden in
the new derived class, then it might introduce a subtle bug.
Prefer providing direct initialization code in constructors [1]; do not depend on runtime polymorphism
(calling virtual methods) inside constructors.

Language Support, Features and Code Examples

The semantics of calling virtual methods from base-class constructors in C++ is different from that of
Java/C#. In C++, any virtual calls will be resolved only to the type of the object being constructed;
however in Java/C#, a virtual method call will be made.
Both the approaches have advantages and disadvantages; before covering those details, let us see an
example from C++ and Java first which shows this difference:
// C++ example
struct base {
base() {
vfun();
}
virtual void vfun() {
cout << “Inside base::vfun\n”;
}
};

struct deri : base {


virtual void vfun() {
cout << “Inside deri::vfun\n”;
}
};

int main(){
deri d;
}

// prints:
// Inside base::vfun

// Java example
class base {
public base() {
vfun();
}
public void vfun() {
System.out.println("Inside base::vfun");
}
}

class deri extends base {


public void vfun() {
System.out.println("Inside deri::vfun");
}
public static void main(String []s) {
deri d = new deri();
}
}
// prints:
// Inside deri::vfun

In C++, when a virtual method call is made from the base class constructor, only the static type of the
object is considered. If the dynamic type was considered and the derived class method is invoked, then
it will possibly result in accessing the un-initialized parts of the derived object, which is not desirable
(this is what precisely happens in case of Java and C#). However, because of this semantics, sometimes
it can happen that the users accidentally end up calling a pure virtual function in C++.
Calling pure virtual function results in undefined behaviour; the usual behaviour for the compilers is to
throw a runtime exception and terminate the program abnormally. Here is an example:
struct base {
base() {
base * bptr = this;
bptr->bar();

// even simpler ...


((base*)(this))->bar();
}
virtual void bar() =0;
};

struct deri: base{


void bar(){ }
};

int main(){
deri d;
}

// g++ output:
// pure virtual method called
// ABORT instruction (core dumped)

The compiler can detect virtual method calls inside the pure virtual function calls, but it cannot
invocations detect indirect invocations. In case there is a temporary variable to have indirect invocation
or a typecast present, then the compiler will not detect call to pure virtual function call.
Note that, if Java/C# like semantics were followed in C++, the overridden method would have been
called which would have avoided this possibility of invoking a pure virtual function.
Coming to Java and C#, since the overridden method is called when a virtual method is called in a base
class constructor, the program can end-up accessing the derived parts, which wouldn’t have been
initialized yet. The following example shows this with an example: Derived class has a data member of
type Integer, which will be initialized only when the constructor of Derived is invoked; however, since
the virtual method foo is called from the base class constructor, the program tries to call toString
method from i which is not initialized yet, resulting in NullPointerException.
// Java code
class Base {
public Base() {
foo();
}
public void foo() {
System.out.println("In Base's foo ");
}
}

class Derived extends Base {


public Derived() {
i = new Integer(10);
}
public void foo() {
System.out.println("In Derived's foo " + i.toString());
}
private Integer i;
}

class Test {
public static void main(String [] s) {
new Derived().foo();
}
}
// this program fails by throwing a NullPointerException

An equivalent program in C# will also fail in the same way by trying to access the un-initialized data
member in Derived object.
[1] Invoking virtual methods in destructors - as in C++ - also doesn’t work well. The object is getting
destroyed and hence the object cannot be expected to be in consistent state, so it will result in defects.

You might also like