如何从基类函数调用覆盖的虚函数?

Posted

技术标签:

【中文标题】如何从基类函数调用覆盖的虚函数?【英文标题】:How to call a overrided virtual function from a base class function? 【发布时间】:2011-11-06 12:49:42 【问题描述】:

我刚刚意识到我将代码简化得太多了,它并没有反映我真正的问题。我很抱歉没有更具体。我实际上尝试做的是:

online Demo

#include<iostream>

class A

    public:
        A();

        virtual void f()= 0;
        void g();
;

A::A()

    g();


void A::g()

    f();


class B : public A

    public:
        B() ;
        void f() ;
;

int main()

    B b;
    return 0;

我猜程序调用了纯虚函数A::f,因为在调用构造函数时还没有创建B

这是正确的吗?我该如何解决这个问题?

请原谅我之前给出了过于简单的问题。

【问题讨论】:

我也在等待回复。根据我对 C++ 的了解,您无法构造一个类实例,其中该类仍有一些未实现的纯虚拟方法.. 您删除的代码中几乎肯定存在错误。 不,这绝对不能编译。也许某些相关程序确实可以编译。如果是这样,请逐字显示。 @Heisenbug +1,我想知道原始海报是如何编译的 我冒昧地修改了您的问题以添加适当的代码示例,并且更新了我的答案来回答它。 【参考方案1】:

Working sample 的代码,在我删除了许多其他错误之后。

#include<iostream>

class A 

    virtual void f()=0;
    public:
    void g();
;

void A::g() 

   f();


class B : public A 


    void f()std::cout<<"Inside B::f";
;

int main() 

    B b;
    b.g();
    return 0;

输出:

内部 B::f

发布您的真实代码,以获得真实答案。


编辑: 现在,您向我们展示了您的真实代码(它有编译错误,我为您修复了它们)。我理解你的问题。

当您使用B b; 创建类B 的对象时,会导致调用基类构造函数A::A(),而后者又调用方法g()。请注意,g() 只是一个基类方法,因此这会导致调用A::g()。这进一步调用f()。现在您的期望是这应该调用B::f(),但它没有。

为什么? 请注意规则,在构造函数或析构函数中,this 指向的对象类型始终是其构造函数/析构函数被调用的类型。

应用上述规则,由于f()A 的构造函数中被调用,this-&gt;f() 调用A::f() 而不是B::f()。此外,由于A::f() 没有定义(因为您没有提供定义)它会导致运行时异常:

调用纯虚方法 在没有活动异常的情况下调用终止。

编译器无法将其检测为编译时错误,因为使用virtual,要调用的函数是在运行时根据this 指向的内容而不是静态确定的。编译器无法检测到这一点。

我该如何克服这个问题? 你不能通过构造函数中的动态调度来做到这一点。 如果您从除构造函数/析构函数之外的任何其他方法调用它,您可以实现并期待您期望的行为。

避免在构造函数和析构函数中调用虚函数,因为它们不会调用您认为它们可能调用的版本。

【讨论】:

【参考方案2】:

如果 B::f 的函数签名与 A::f 匹配,则在 A::g 中使用 f() 应该按照您的意愿调用 B::f。在您上面的示例中,它们确实匹配,并且 A::g 应该调用 B::f。

如果您的真实函数签名比上面给出的示例更复杂,请确保它们的签名完全匹配,否则编译器会将 B::f 视为新函数而不是 A::f 的覆盖。

*:严格来说,返回类型可能会略有不同,但我认为这与这里无关

【讨论】:

【参考方案3】:

删除编译器错误后,your code works fine.

【讨论】:

【参考方案4】:

从概念上讲,这应该可行。我已经很久没有接触过 C++ 了,但这与 C# 中的这种情况应该没有太大的不同:

public class MyBase

    public virtual void PrintName()  
    public void DoWork()
    
        PrintName();
    


public class MyDerivative : MyBase

    public override void PrintName()
    
        Console.WriteLine("MyDerivative");
    

【讨论】:

当然,在 C# 中,您会将 MyBase 和 MyBase::PrintName 标记为抽象。【参考方案5】:
#include <iostream>

class A 
public:
    virtual void f() = 0;
    void g();
;

void A::g() 
    std::cout << "A::g" << std::endl;
    this->f();


class B : public A 
public:
    virtual void f();
;

void B::f()

    std::cout << "B::f" << std::endl;


int main() 
    B b;
    b.g();
    return 0;

【讨论】:

【参考方案6】:

在源代码中添加:

void B::f()

    printf("im B::f\n");

你的程序应该可以工作了。

你不能创建 A 的实例,因为有一个纯虚方法。

【讨论】:

以上是关于如何从基类函数调用覆盖的虚函数?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 中如何调用基类的虚函数?

如何从基类调用派生类函数?

从基类构造函数调用纯虚函数

如何从基类调用派生赋值运算符?

从基类调用派生类函数

从基类调用静态函数