【问题标题】:Most derived class cannot compile if virtual function not implemented, but can compile if one base class does not implement the virtual function大多数派生类如果没有实现虚函数就不能编译,但是如果一个基类没有实现虚函数就可以编译
【发布时间】:2018-06-20 14:44:59
【问题描述】:

我有一个包含 4 个类的 C++ 程序:Person、Student、Employee 和 PartTimeStudent。

Student 和 Employee 都派生自 Person,而 PartTimeStudent 派生自所有 3 个类(使其成为派生最多的类)。 Person、Student 和 Employee 还有一个名为 VDescribe() 的派生函数。

请看下面的代码:

class Person
{
    ...    
    virtual void VDescribe();
    ...
};

class Student : virtual public Person
{
    ...    
    virtual void VDescribe();
    ...
};

class Employee : virtual public Person
{
    ...    
    virtual void VDescribe();
    ...
};

class PartTimeStudent : virtual public Person,
    virtual public Student,
    virtual public Employee
{
    ...
};

注意:在上面的代码 sn-p 中,我省略了构造函数、析构函数和成员变量,因为它们与手头的问题无关。

当我尝试编译代码时,出现以下错误:

override of virtual function "Person::VDescribe" is ambiguous

'PartTimeStudent': ambiguous inheritance of 'void Person::VDescrive(void)'

'PartTimeStudent': ambiguous inheritance of 'void Person::VDescribe(void)'

但是,只有在 Student 和 Employee 都实现 VDescribe() 时才会发生这种情况。如果其中一个类没有实现 VDescribe(),则编译成功。我仍然收到警告,例如如果我从 Employee 中省略 VDescribe(),则会出现以下警告:

'PartTimeStudent': inherits 'Student::Student::VDescribe' via dominance

请问为什么会这样?我想知道如果所有3个类都实现了VDescribe(),为什么PartTimeStudent无法编译,但是如果Student或Employee没有该功能,PartTimeStudent仍然可以编译。

【问题讨论】:

  • 简单来说问题是:当有两种可能的选择时,VDescribe 应该继承哪个PartTimeStudent
  • ^- 这个。如果您觉得回答很重要,请想象一下语言设计者的感受。
  • @Angew,错误以文本形式发布。
  • @tobi303 3 个选项 - 它也继承了 Person 本身!
  • @UKMonkey 感谢您向我保证我不是这里唯一的书呆子:P

标签: c++ multiple-inheritance virtual-functions overriding virtual-inheritance


【解决方案1】:

两个覆盖

想象一下StudentEmployee 实现VDescribe 的scanario,而PartTimeStudent 没有实现它。您希望这段代码的行为如何:

PartTimeStudent pts;
pts.VDescribe();

应该调用VDescribe 的哪个实现?它是模棱两可的,这正是编译错误的原因。

一个覆盖

Employee 不覆盖VDescribe 时,情况有点不同。 PartTimeStudent 则有以下函数可继承:

  • Person::VDescribeStudent::VDescribe 覆盖,来自Student
  • Person::VDescribe 未被覆盖,来自 Employee
  • Person::VDescribe 未被覆盖,来自 Person

在这种情况下,Student::VDescribe 覆盖 Person::VDescribe 并且是明确的覆盖器,因此编译器可以使用它。但是,它警告您有一个替代继承路径没有通过这个覆盖。此警告在实践中不是很有用,是我经常禁用的少数警告之一。


如果您希望您的代码在StudentEmployee 都覆盖VDescribe 的情况下也能编译,那么您实际上也必须在PartTimeStudent 中覆盖它。然后该函数将具有明确的最终覆盖器,并且代码将编译得很好。您可以使用限定名称调用一个或两个继承的实现。示例:

void PartTimeStudent::VDescribe()
{
  Student::VDescribe();
  if (isWorking()) Employe::VDescribe();
}

【讨论】:

  • 我从您的回答中了解到:如果 VDescribe() 从 Person 到 Student/Employee 再到 PartTimeStudent 的继承路径只有一条,则编译成功,因为 PartTimeStudent 使用了 VDescribe 的最衍生版本(个人或员工)。但是如果路径中有“分裂”,即在 Person 之后,Student 和 Employee 都支持 VDescribe()。在这种情况下,编译器不知道 PartTimeStudent 将继承哪个版本,从而导致错误。请问你是不是这个意思?
  • "这个警告在实践中不是很有用" 这是有史以来最愚蠢的警告。编译器可以很好地输出“你使用的是一种复杂的语言,你会尝试 GW BASIC 吗?”
猜你喜欢
  • 1970-01-01
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
  • 2013-06-02
  • 1970-01-01
  • 2019-04-14
  • 2018-10-14
相关资源
最近更新 更多