是否需要在派生类中实现所有虚拟功能?


91

这似乎是一个简单的问题,但在其他任何地方都找不到答案。

假设我有以下内容:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

派生类不实现bar()函数可以吗?如果不是,我的所有派生类都需要bar()函数,但是有些需要。是需要在派生类中实现抽象基类的所有虚函数,还是仅在纯虚函数中实现?谢谢

Answers:


82

派生类也没有必须实现所有的虚函数本身。他们只需要实现纯代码1表示Derived问题所在的班级是正确的。它继承bar其祖先类的实现,Abstract。(这假定Abstract::bar是在某个地方实现的。问题中的代码声明了方法,但未定义方法。您可以按Trenki的答案所示内联定义它,也可以单独定义它。)


1即使如此,仅当派生类要实例化时。如果派生类不是直接实例化的,而是仅作为更多派生类的基类存在的,则这些类负责实现其所有纯虚方法。就像基类一样,允许层次结构中的“中间”类保留一些未实现的纯虚拟方法。如果“中间”类确实实现了纯虚拟方法,则其后代将继承该实现,因此他们不必自己重新实现它。


3
甚至只有打算实例化它们(纯虚拟函数的实现)时(与本身是抽象基类相反)。
Christian Rau 2012年

1
这就是我所想的。但是在我的项目中这样做,并且收到一个链接错误,指出Derived :: bar();有一个“未解析的外部符号”;但是我从未在Derived中声明bar,那么链接器为什么要寻找函数体?
mikestaub

1
@pixelpusher当然Derived::bar有一个函数体,即Abstract::bar。因此,似乎在其中定义的翻译单元(甚至在任何地方都定义了吗?)未链接到调用它的翻译单元中。
Christian Rau 2012年

2
@罗伯:They only need to implement the pure ones.这是误导。派生类不一定需要实现pure虚函数。
纳瓦兹2012年

我很感谢您的帮助,但@trenki真是令人震惊。尽管您也是正确的克里斯蒂安·劳(Christian Rau),但尚未定义。
mikestaub 2012年

47

仅纯虚拟方法必须在派生类中实现,但是您仍然需要其他虚拟方法的定义(而不仅仅是声明)。如果您不提供,链接程序可能会抱怨。

因此,只需将{}可选的虚方法放在后面,即可得到一个空的默认实现:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

不过,涉及更多的默认实现将放入单独的源文件中。


7

ISO C ++标准规定必须定义非纯虚拟类的所有虚拟方法。

简单地说,规则是:
如果派生类覆盖了基类虚方法,则它也应提供一个定义;否则,基类应提供该方法的定义。

按照代码示例中的上述规则,virtual void bar();需要在Base类中进行定义。

参考:

C ++ 03标准:10.3虚函数[class.virtual]

必须定义在一个类中声明的虚函数,或在该类中声明为纯(10.4),或两者都声明。但不需要诊断(3.2)。

因此,您应该使函数成为纯虚函数,或者为其提供定义。

gcc的常见问题doccuments它还有:

ISO C ++标准规定,必须定义非纯虚拟类的所有虚拟方法,但对于违反此规则不需要任何诊断[class.virtual]/8。基于此假设,GCC将仅在隐式定义的构造函数,赋值运算符,析构函数和定义其第一个此类非内联方法的转换单元中的类的虚拟表中发出该类。

因此,如果您未能定义此特定方法,则链接器可能会抱怨缺少针对显然不相关的符号的定义。不幸的是,为了改善此错误消息,可能有必要更改链接器,但并非总是如此。

解决方案是确保定义了所有非纯虚拟方法。请注意,即使已将析构函数声明为pure-virtual,也必须对其进行定义[class.dtor]/7


3

是的,那很好。您只需要实现任何纯虚函数即可实例化从抽象基类派生的类。


1

是的,正确的是派生类必须重写父类中的纯虚函数。具有纯虚函数的父类仅被称为抽象类,因为它的子类必须给出自己的纯虚函数的主体。

对于普通虚拟功能:-不必进一步覆盖它们,因为某些子类可能具有该功能,而某些子类可能没有。

虚拟功能机制的主要目的是运行时多态性,无论纯虚拟功能(抽象类)的主要目的是否是要强制具有与自己的身体同名的功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.