c++ 基类的虚函数调用

shstlldc  于 2023-01-15  发布在  其他
关注(0)|答案(9)|浏览(279)

假设我们有:

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

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

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

将从Base::f()调用哪个g()Base::g()还是Derived::g()
谢谢你...

slsn1g29

slsn1g291#

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

Base::g();

如果你想调用派生版本,但仍然想让基版本被调用,那么安排g的派生版本在它的第一条语句中调用基版本:

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

来自基类的函数可以调用虚方法并且控制权被转移到派生类的事实被用在模板方法设计模式中。它通常被称为Non-Virtual-Interface,它也广泛用于C标准库中(例如,C流缓冲区具有函数pub...,该函数调用执行真实的工作的虚函数。例如,pubseekoff调用受保护的seekoff)。我在下面的回答中举了一个例子:如何验证对象的内部状态?

pgpifvop

pgpifvop2#

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

lrpiutwd

lrpiutwd3#

pBase是指向基址的指针。pBase = new Derived返回指向Derived的指针- Derived是基址。
因此pBase =新衍生是有效的。
pBase引用了一个Base,因此它会将Derived视为Base。
pBase-〉f()将调用Derive::f();
然后我们在代码中看到:
推导::f()--〉基::f()--〉g()--但哪个g??
它调用Derive::g(),因为这是pBase“指向”的g。
答案:推导::g()

puruo6ea

puruo6ea4#

嗯......我不确定这个是否可以编译。下面,

Base *pBase = new Derived;

无效,除非您具有:

Class Derived : public Base

你指的是想要吗?如果你指的是想要,

pBase->f();

然后调用堆栈将如下所示:

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

zpgglvta5#

由于您已经将g()定义为虚拟的,因此无论代码当前访问的是什么类型,都将在类的vtable中查找并调用派生程度最高的g()。
请参见C++ FAQ on virtual functions

of1yzvn4

of1yzvn46#

实际运行代码显示Derived::g()被调用。

5lwkijsr

5lwkijsr7#

如果在成员函数中,将调用派生类的g()。
如果在构造函数或析构函数中,则调用基类的g()。
https://www.geeksforgeeks.org/calling-virtual-methods-in-constructordestructor-in-cpp/

// 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
snvhrwxg

snvhrwxg9#

将调用派生类的方法。
这是因为在具有虚函数的类和覆盖这些函数的类中包含了vtable。(这也称为动态分派。) 下面是实际情况:为Base创建一个vtable,为Derived创建一个vtable,因为每个类只有一个vtable。由于pBase调用的函数是虚拟的且被覆盖,因此将调用指向Derived的vtable的指针。将其称为d_ptr,也称为vpointer:

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

现在,d_ptr调用Derived::f()Derived::f()调用Base::f()Base::f()查看vtable以确定使用哪个g(),因为vpointer只知道Derived中的g(),所以我们使用Derived,因此,Derived::g()被调用。

相关问题