C++ 来自基类的虚拟函数调用

C++ 来自基类的虚拟函数调用,c++,polymorphism,virtual,C++,Polymorphism,Virtual,假设我们有: Class Base { virtual void f(){g();}; virtual void g(){//Do some Base related code;} }; Class Derived : public Base { virtual void f(){Base::f();}; virtual void g(){//Do some Derived related code}; }; int main() { B

假设我们有:


Class Base
{   
    virtual void f(){g();};
    virtual void g(){//Do some Base related code;}
};

Class Derived : public Base
{   
    virtual void f(){Base::f();};
    virtual void g(){//Do some Derived related code};
};

int main()
{
    Base *pBase = new Derived;
    pBase->f();
    return 0;  
}

将从
Base::f()
调用哪个
g()
<代码>基::g()或
派生::g()


谢谢

将调用派生类的g。如果要调用基函数中的函数,请调用

Base::g();
相反。如果要调用派生版本,但仍要调用基本版本,请安排g的派生版本在其第一条语句中调用基本版本:

virtual void g() {
    Base::g();
    // some work related to derived
}

模板方法设计模式中使用了这样一个事实:基函数可以调用虚方法,控制权被转移到派生类中。对于C++,它更为著名。它在C++标准库中也有广泛的应用(C++流缓冲区,例如函数,代码,代码,…,代码),调用真正的工作的虚拟函数。例如,代码> PUBEXKOOFF < /代码>调用受保护的<代码> SekOff<<代码>。我在这个答案中写了一个这样的例子:

我认为您试图发明因为您已经将g()定义为虚拟的,最派生的g()将在类的vtable中查找并调用,而不管您的代码当前访问它的类型是什么


请参阅。

好的。。。我不确定这是否应该编译。以下:

Base *pBase = new Derived;
无效,除非您有:

Class Derived : public Base
你的意思是想要吗?如果这是你的意思

pBase->f();
然后调用堆栈将如下所示:

Derived::f()
    Base::f()
        Derived::g()

实际运行代码表明调用了派生的::g()。 pBase=new-Derived返回指向派生is-a基的指针

因此pBase=new-Derived是有效的

pBase引用了一个基,所以它看起来就像是一个基一样

pBase->f()将调用派生::f()

然后我们在代码中看到:

派生::f()-->Base::f()-->g()-但哪个g

它调用了派生::g(),因为pBase“指向”的是g


答:派生::g()

它是派生::g,除非在Base的构造函数中调用g。因为基本构造函数是在构造派生对象之前调用的,所以不能从逻辑上调用派生的::g,因为它可能会操作尚未构造的变量,所以将调用Base::g。

将调用派生类的方法

这是因为在具有虚拟函数的类和重写这些函数的类中包含vtable。(这也称为动态调度。)实际情况如下:为
Base
创建vtable,为
派生的
创建vtable,因为每个类只有一个vtable。由于
pBase
调用的函数是虚函数和超码函数,因此会调用指向
派生的
vtable的指针。称之为
d_ptr
,也称为vpointer:

int main()
{
    Base *pBase = new Derived;
    pBase->d_ptr->f();
    return 0;  
}
现在d_ptr调用
Derived::f()
,调用
Base::f()
,然后查看vtable以查看要使用的
g()
。因为vpointer只知道
Derived
中的
g()
,所以我们使用的就是这个。因此,将调用派生的::g()。

g()派生类将在成员函数中调用

如果在构造函数或析构函数中,将调用基类的g()


请使用上面有1/0'ers的按钮来很好地格式化代码。(我编辑了它,但是OP回滚了它。所以我自己不会再编辑它了)请注意,你给出了一个内存泄漏的例子。您在main中有一个被遗忘的delete。很好地解释了构造函数中发生的事情。
Scott Meyers说,有趣的是,我发现GCC 4.8.2有一个问题:
Base*pBase=(Base*)(void*)new-Derived尝试从基类调用纯虚函数。如果在构造函数中调用,将调用g()基类,因为派生类现在未构造。
// calling virtual methods in constructor/destructor
#include<iostream> 
using namespace std; 

class dog 
{ 
public: 
    dog()  
    { 
        cout<< "Constructor called" <<endl; 
        bark() ; 
    } 

    ~dog() 
    {  
        bark();  
    } 

    virtual void bark() 
    {  
        cout<< "Virtual method called" <<endl;  
    } 

    void seeCat()  
    {  
        bark();  
    } 
}; 

class Yellowdog : public dog 
{ 
public: 
        Yellowdog()  
        { 
            cout<< "Derived class Constructor called" <<endl;  
        } 
        void bark()  
        { 
            cout<< "Derived class Virtual method called" <<endl;  
        } 
}; 

int main() 
{ 
    Yellowdog d; 
    d.seeCat(); 
} 
Constructor called
Virtual method called
Derived class Constructor called
Derived class Virtual method called
Virtual method called