简体   繁体   中英

Dynamic binding inside constructor for virtual Function in C++

As per the standard, we know that constructor always go for an early binding of a virtual function inside them because they don't have complete idea the derived class hierarchy downside.

In this case if early binding is used inside my base constructor, I have passed a derived object to a base class pointer which is completely acceptable (an upcasting is done here). If early binding is used the selection of the virtual function should be based on the type of the pointer (which is Base * here) but not the content of the pointer(the object pointed by the pointer because we don't know the exact object being pointed). In that case since the pointer type is Base * we should have invoked only Base class virtual function in both cases. Could some one please clarify this?

I think dynamic binding is used here rather than early binding. Please correct me if my understanding is wrong.

The first line of the output which invokes base is completely fine

class Base
    {
        public:
        Base(){
            fun();
        }
        Base(Base *p)
        {
            p->fun();
        }
        virtual void fun()
        {
            cout<<"In Base"<<endl;
        }
    };

    class Derived : public Base
    {
        public:
        void fun()
        {
            cout<<"In Derived"<<endl;
        }
    };

    int main()
    {
        Derived d;
        Base b(&d);
    }

O/P :

In Base
In Derived

The rule for virtual calls within a constructor body applies to an object currently being constructed , because that object is not yet considered to be an object of any derived class. (And there's a similar rule for an object currently being destroyed.) It has little to do with "early binding" in the sense of using a compile-time type, such as the syntax ClassName::member_func() forces.

Your code has two different objects d and b , and the constructor of d has entirely finished by the time you get to the p->fun(); line.

In detail:

  1. The program enters main .
  2. The object d is created using the implicitly declared default constructor of Derived .
  3. The first thing Derived::Derived() does is create the base class subobject, by calling the default constructor Base::Base() .
  4. The body of Base::Base() calls fun() . Since we have not yet entered the body of the Derived::Derived() constructor, this virtual lookup invokes Base::fun() .
  5. Base::Base() finishes.
  6. The body of Derived::Derived() , which is empty, executes and finishes.
  7. Back in main , the object b is created by passing a pointer to d to the constructor Base::Base(Base*) .
  8. The body of Base::Base(Base *p) calls p->fun() . Since p is a pointer to d , which is already a completely constructed object of type Derived , this virtual lookup invokes Derived::fun() .

Contrast with this slightly different example, where we define a default constructor of Derived to pass this (implicitly converted to Base* ) to the constructor for the Base subobject. (This is valid, though could be risky if the pointer were used in other ways, such as in an initializer for a base or member of Base .)

#include <iostream>
using std::cout;
using std::endl;

class Base
{
public:
    Base(){
        fun();
    }
    Base(Base *p)
    {
        p->fun();
    }
    virtual void fun()
    {
        cout<<"In Base"<<endl;
    }
};

class Derived
{
public:
    Derived() : Base(this) {}
    virtual void fun() override
    {
        cout << "In Derived" << endl;
    }
};

int main()
{
    Derived d;
}

This program will print just "In Base", since now in Base::Base(Base *p) , p does point at the same object which is currently being constructed.

The reason is that C++ classes are constructed from Base classes to derived classes and virtual call table of the complete object is created when the object creation process is completed. Therefore, the base class function is called in the code excerpt above. Unless otherwise mandatory, you should never make virtual function calls in the constructor. Below is an excerpt from Bjarne Stroustrup's C++ Style and Technique FAQ :

  • In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn't yet happened. Objects are constructed from the base up, “base before derived”.

  • Destruction is done “derived class before base class”, so virtual functions behave as in constructors: Only the local definitions are used – and no calls are made to overriding functions to avoid touching the (now destroyed) derived class part of the object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM