64

假设我们有:


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;  
}

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

谢谢...

4

9 回答 9

65

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

Base::g();

反而。如果您想调用派生版本,但仍希望调用基本版本,请安排 g 的派生版本在其第一条语句中调用基本版本:

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

模板方法设计模式中使用了来自基类的函数可以调用虚方法并将控制权转移到派生类的事实。对于 C++,它更广为人知的是Non-Virtual-Interface。它在 C++ 标准库中也被广泛使用(例如,C++ 流缓冲区具有pub...调用执行实际工作的虚函数的函数。例如pubseekoff调用 protected seekoff)。我在这个答案中写了一个例子:你如何验证对象的内部状态?

于 2008-12-29T09:52:41.680 回答
17

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

于 2013-09-19T04:18:01.497 回答
6

pBase 是一个指向基址的指针。pBase = new Derived 返回一个指向 Derived - Derived is-a Base 的指针。

所以 pBase = new Derived 是有效的。

pBase 引用了一个 Base,因此它会将 Derived 视为一个 Base。

pBase->f() 将调用 Derive::f();

然后我们在代码中看到:

Derive::f() --> Base::f() --> g() - 但是哪个 g??

好吧,它调用 Derive::g() 因为那是 pBase “指向”的 g。

答案:派生::g()

于 2010-05-28T20:56:32.187 回答
2

嗯......我不确定这应该编译。以下,

Base *pBase = new Derived;

无效,除非您有:

Class Derived : public Base

是要你的意思吗?如果这是你的意思,

pBase->f();

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

Derived::f()
    Base::f()
        Derived::g()
于 2008-12-29T19:20:54.527 回答
1

由于您已将 g() 定义为虚拟,因此将在类的 vtable 中查找最派生的 g() 并调用,无论您的代码当前正在访问它的类型如何。

请参阅有关虚函数的 C++ 常见问题解答

于 2008-12-29T10:15:35.330 回答
1

实际运行您的代码表明调用了 Derived::g() 。

于 2008-12-30T07:30:04.977 回答
0

我认为您试图发明模板方法模式

于 2008-12-29T10:06:30.340 回答
0

将调用派生类的方法。

这是因为在具有虚函数的类和覆盖这些函数的类中包含了虚表。(这也称为动态分派。)这是真正发生的事情:创建Base一个 vtable 并创建一个 vtable Derived,因为每个类只有一个 vtable。因为pBase正在调用一个虚函数并被覆盖,所以调用了一个指向 vtable 的指针Derived。调用它d_ptr,也称为 vpointer:

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

现在 d_ptr 调用Derived::f(),调用Base::f(),然后查看 vtable 以查看g()要使用的内容。因为 vpointer 只知道g()in Derived,所以我们使用的就是那个。因此,Derived::g()被称为。

于 2016-06-23T01:51:19.850 回答
0

如果在成员函数中,将调用派生类的 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
于 2020-05-03T09:58:25.213 回答