1

I was expecting derived method get() will be called from constructor of A. Wondering why is this not happening?

Method get() is virtual in base class so derive class B will override this method.

#include <iostream>
using namespace std;

class A {
protected:

    virtual int get() {
        cout<<" in A::get "<<endl;
        return 0;
    }
public:
    A() {
        get();
    }
};

class B : public A {
public:
    B():A() {}

protected:  
    int get() override{
        cout<<"in B:get() "<<endl;
        return 0;
    }
};


int main() {
A *a;  a = new B();
return 0;
}
Alyafey
  • 1,455
  • 3
  • 15
  • 23
Vikas Kumar
  • 241
  • 1
  • 2
  • 6

2 Answers2

2

While it's possible and sometimes a good choice, it's most of the time a bad idea to call virtual functions in a constructor. Only do this if you really understand what that means. The same applies for calling virtual functions in destructors.

When the instance of class B is constructed, it first constructs an A. During this phase, the object is only identified as an instance of A rather than B. So at that time, the object has a virtual function table of class A. This means that every virtual function call will resolve to functions of class A (or super classes); the same rules apply as if you would only construct an instance of A.

For a full explanation, please read When my base class's constructor calls a virtual function on its this object, why doesn't my derived class's override of that virtual function get invoked?

Even if it was possible to call the function B::get() within the constructor of A (example: http://ideone.com/sF3411), that would be undefined behavior, since when the constructor of A is executed, the this pointer is not yet pointing to an instance of B, it's only "in preparation" if you will. The linked code might work, but it's a hack and exposes undefined behavior.

leemes
  • 44,967
  • 21
  • 135
  • 183
1

Apart from the C++ FAQ link from leemes, C++ standard prevent it to be called, I will quote the standard.

The following says that, virtual member functions can be called within constructor/destructor, but they act as "not virtual", which you already know in the C++ FAQ.

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

It actually also says that, when calling virtual function from a pointer (to itself) with a type that is not direct base class of itself (in multiple inheritance), the behaviour is undefined.

Example (from standard)

struct V {
  virtual void f();
  virtual void g();
};
struct A : virtual V {
  virtual void f();
};
struct B : virtual V {
  virtual void g();
  B(V*, A*);
};
struct D : A, B {
  virtual void f();
  virtual void g();
  D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
  f(); // calls V::f, not A::f
  g(); // calls B::g, not D::g
  v->g(); // v is base of B, the call is well-defined, calls B::g
  a->f(); // undefined behavior, a’s type not a base of B
}

The above rules apply to other dynamic binding stuff, including typeid, meaning that you can't use typeid to differentiate derived class type in base constructor.

The typeid operator (5.2.8) can be used during construction or destruction (12.6.2). When typeid is used in a constructor (including the mem-initializer or brace-or-equal-initializer for a non-static data member) or in a destructor, or used in a function called (directly or indirectly) from a constructor or destructor, if the operand of typeid refers to the object under construction or destruction, typeid yields the std::type_info object representing the constructor or destructor’s class. If the operand of typeid refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor’s class nor one of its bases, the result of typeid is undefined.

user534498
  • 3,926
  • 5
  • 27
  • 52