3

Maybe this was covered in some other topic. But I did not find any satisfactory answer. Could somebody explain me following. I have following code:

#include <iostream>

class Base {
public:
   Base() {
      foo();
   }

   virtual void foo() { 
      std::cout << "Base::foo()" << std::endl; 
   }
};

class Derived : public Base {
public:
   Derived(): Base() {}

   virtual void foo() { 
      std::cout << "Derived::foo()" << std::endl; 
   }
};

int main() {
   Derived* p = new Derived();
}

Now my question is why does the Base creator calls foo method which is in the Base and not in the Derived class, although it is overridden in the Derived class?

joe_specimen
  • 295
  • 3
  • 19

4 Answers4

2

Inside a constructor, the class of the object being constructed is that of the class to which the constructor belongs. In this case, inside the Base constructor, the class of the object being constructed is Base. You cannot make virtual calls from inside a constructor, they are all statically resolved.

It would be quite dangerous to allow virtual calls inside a constructor. Inside a constructor, the execution order is:

  • Base class(es) constructor(s)
  • Data member constructors, in the order the data members are declared in the class definition
  • Constructor body

Of course, this is recursive: the execution order inside each base class constructor is the same.

Now, imagine what would happen if Derived::foo() used data members defined in Derived. Those data members would not have been constructed yet when the Base constructor is executed. What would happen in that case? The dreaded undefined behaviour, of course.

For this reason, calling virtual functions inside a constructor is not generally a good idea. As you can see, the function called may not be the one expected (since there is actually no virtual call); but making that virtual call might easily lead into undefined behaviour, which is always bad.

Gorpik
  • 10,940
  • 4
  • 36
  • 56
1

Frome here:

Only the local definitions are used – and no calls are made to overriding functions to avoid touching the derived class part of the object.

In 'ctors only local definition are used (local in sense of scope of that class).

That is done in order to avoid touching derived class part of the object which are potentially not initialized yet.

The example is self-explanatory:

 class B {
    public:
        B(const string& ss) { cout << "B constructor\n"; f(ss); }
        virtual void f(const string&) { cout << "B::f\n";}
    };

 class D : public B {
    public:
        D(const string & ss) :B(ss) { cout << "D constructor\n";}
        void f(const string& ss) { cout << "D::f\n"; s = ss; }
    private:
        string s;
    };

If D::f was called in the constructor B::B then it would try to assign a value to an uninitialized string s (because the constructor D::D wouldn't called yet).

That's why C++ standard behaviour has been so defined.

BiagioF
  • 9,368
  • 2
  • 26
  • 50
1

Virtual function calls in C++ are resolved in accordance with the dynamic type of the object used in the call (this is what differentiates virtual functions from non-virtual ones).

When the constructor (or destructor) of class Base is active, the dynamic type of the object is always considered to be Base, even if that Base object is "embedded" into some larger derived object (like Derived in your case). For this reason all virtual calls made while Base's constructor is active will resolve to the members of Base.

Note that the virtual call mechanism is not formally disabled in this case. (It is not correct to claim that virtual calls made from constructors are resolved "statically"). The virtual call mechanism still works as usual. It is just that the hierarchy tree is "capped"/"trimmed" at the class whose constructor is currently active.

The rationale behind this rule is pretty natural: while Base constructor is active, Derived is not constructed yet. Accessing any members of Derived would be dangerous. Moreover, trying to work around this restriction (which is possible) usually leads to undefined behavior. The same logic symmetrically applies to destructors.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
1

It is bad pratice to call virtual functions inside of constructor. I just give simple example, which will show disadvantages of this approach (Note: It is about c++ (other languages can use different implementation).

Order of calling constructors in your code is:

1) Base

2) Derived

At the moment of calling Base constructor, member specified in Derived class is not created. Suppose, you can use function, overrided in Derived class. In this case you can invoke functions, which will have access to NOT CREATED DATA (note, at the moment Derived class is not created). Obviously, it is too dangerous. At that point it seems logicaly to call function, which can work with created data (in this case it is data of Base class)

Alex Aparin
  • 4,393
  • 5
  • 25
  • 51