如何从基类函数调用覆盖的虚函数?
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->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 的实例,因为有一个纯虚方法。
【讨论】:
以上是关于如何从基类函数调用覆盖的虚函数?的主要内容,如果未能解决你的问题,请参考以下文章