C++ 从基类调用虚函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/397404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:07:58  来源:igfitidea点击:

virtual function call from base class

c++polymorphismvirtual

提问by Gal Goldman

Say we have:

假设我们有:


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

Which g()will be called from Base::f()? Base::g()or Derived::g()?

哪个g()会被调用Base::f()Base::g()或者Derived::g()

Thanks...

谢谢...

回答by Johannes Schaub - litb

The g of the derived class will be called. If you want to call the function in the base, call

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

Base::g();

instead. If you want to call the derived, but still want to have the base version be called, arrange that the derived version of g calls the base version in its first statement:

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

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

The fact that a function from the base can call a virtual method and control is transferred into the derived class is used in the template method design pattern. For C++, it's better known as Non-Virtual-Interface. It's widely used also in the C++ standard library (C++ stream buffers for example have functions pub...that call virtual functions that do the real work. For example pubseekoffcalls the protected seekoff). I wrote an example of that in this answer: How do you validate an object's internal state?

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

回答by Syed Lavasani

It is the Derived::g, unless you call g in Base's constructor. Because Base constructor is called before Derived object is constructed, Derived::g can not logically be called cause it might manipulate variables that has not been constructed yet, so Base::g will be called.

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

回答by Jacob

pBase is a pointer to a base. pBase = new Derived returns a pointer to a Derived - Derived is-a Base.

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

So pBase = new Derived is valid.

所以 pBase = new Derived 是有效的。

pBase references a Base, so it will look at Derived as if it were a Base.

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

pBase->f() will call Derive::f();

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

Then we see in the code that:

然后我们在代码中看到:

Derive::f() --> Base::f() --> g() - but which g??

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

Well, it calls Derive::g() because that is the g that pBase "points" to.

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

Answer: Derive::g()

答案:派生::g()

回答by user48956

Well... I'm not sure this should compile. The following,

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

Base *pBase = new Derived;

is invalid unless you have:

无效,除非您有:

Class Derived : public Base

Is it want you meant? If this is want you meant,

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

pBase->f();

Then the call stack would go like this:

然后调用堆栈会像这样:

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

回答by KJAWolf

Actually running your code shows that Derived::g() is called.

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

回答by Thorsten79

As you have defined g() to be virtual, the most derived g() will be looked up in the vtable of the class and called regardless of the type your code is currently accessing it.

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

See the C++ FAQ on virtual functions.

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

回答by Evgeny Lazin

I think you trying to invent Template Method Pattern

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

回答by Jossie Calderon

The derived class' method will be called.

派生类的方法将被调用。

This is because of the inclusion of vtables within classes that have virtual functions and classes that override those functions. (This is also known as dynamic dispatch.)Here's what's really going on: a vtable is created for Baseand a vtable is created for Derived, because there is only one vtable per class. Because pBaseis calling upon a function that is virtual and overrode, a pointer to the vtable for Derivedis called. Call it d_ptr, also known as a vpointer:

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

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

Now the d_ptr calls Derived::f(), which calls Base::f(), which then looks at the vtable to see what g()to use. Because the vpointer only knows g()in Derived, that's the one we use. Therefore, Derived::g()is called.

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

回答by lbsweek

g() of derived class will be called if in member function.

如果在成员函数中,将调用派生类的 g()。

g() of base class will be called if in constructor or destructor.

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

https://www.geeksforgeeks.org/calling-virtual-methods-in-constructordestructor-in-cpp/

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

output:

输出:

Constructor called
Virtual method called
Derived class Constructor called
Derived class Virtual method called
Virtual method called