从派生构造函数调用基类的虚函数

时间:2018-11-16 09:04:58

标签: c++ function constructor virtual

我知道从构造函数/析构函数调用虚拟函数可以解决早期绑定问题。但是我在这里有一个问题。看下面的代码

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

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

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

O / P是:在基地

我在这里的疑问是,编译器可能正在使用动态绑定而不是早期绑定。请纠正我,我错了,但我需要清楚地说明编译器如何在构造函数中执行早期绑定?

如果该方法不是构造函数,则编译器会将此语句p-> fun转换为

fetch the VPTR at run time (This vptr will have the derived class VTABLE address)

invoke method at vptr + offset 

hence the right virtual function is invoked.

但由于它是构造函数,编译器会停止考虑虚拟机制并简单地忽略指针类型,并将上面的语句p-> fun()替换为obj.fun()(在内部将其视为通过适当的方式调用)对象)

因为即使您进行早期绑定或后期绑定,结果也是相同的(调用本地fun())

如果构造函数内部的早期绑定机制调用的是函数的本地版本,那么我们如何调用非派生函数的基本版本(我知道派生包含base sub对象,但如果构造函数在虚函数的构造函数内执行早期绑定,则需要知道调用基本版本而不是本地/派生函数的原因)

请帮助

2 个答案:

答案 0 :(得分:2)

因为您将实际的Base传递给创建者(而不是指针或引用),所以您拥有一个实际的Base实例-将指针投射到Derived*是无效。

答案 1 :(得分:0)

在您的示例中,Derived的构造函数调用类型为fun()的对象obj的方法Base,您将其作为参数传递给了Derived::Derived。这与您正在构造的Derived实例无关,因此您只需获得对Base::fun()的调用。

如果您只是简单地在fun中调用方法Derived::Derived(使用或不使用this->),最终将在Derived中调用该方法,请参见以下示例:

#include <iostream>

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

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

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

    return 0;
}

输出:

In Derived

另一种情况(也许是您想到的)是在Base类中调用虚拟方法时。然后,在创建Derived变量时,将调用Base的构造函数。但是,此时Derived尚未创建,因此Base类的构造函数中的任何虚拟调用都将解析为Base 中的方法 。 请参见讨论here,来自B. Stroustrup网站的C++ FAQFAQ on the isocpp网站。

最终创建Derived对象后,虚拟调用将照常工作。

以下示例说明了这种情况

#include <iostream>

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

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

int main()
{
    std::cout << "About to create Base: ";
    Base b;
    std::cout << "About to create Derived: ";
    Derived d(b);

    std::cout << "Calling b.callfun(): ";
    b.callfun();
    std::cout << "Calling d.callfun(): ";
    d.callfun();

    return 0;
}

输出:

About to create Base: In Base
About to create Derived: In Base
Calling b.callfun(): In Base
Calling d.callfun(): In Derived