C++ 菱形问题

2024年8月28日 | 阅读 7 分钟

在使用多重继承时,菱形问题可能会出现在计算机语言中,尤其是在 C++ 中。当代码非常长时,C++ 中的多重继承通常被用作一种技术手段。因此,为了组织程序和源代码,我们使用类。然而,如果处理不当,多重继承可能会带来问题。菱形问题主要存在于这些难题中。本教程将重点介绍菱形问题的主要原因、它如何由多重继承引起,以及解决它所需的所有方法。

代码的系统要求

您需要在虚拟机上安装并运行 Ubuntu 系统,以便在 Linux 操作系统下运行与“C++ 菱形继承”相关的应用程序。这需要两个工具。一个是任意的编辑工具;因此,我们将使用 Linux 内置的“文本编辑器”。您也可以使用其他喜欢的编辑工具。第二个工具是 Ubuntu 终端,您将用它来运行程序并查看输出。由于“菱形问题”是在源代码中存在继承时出现的,我们将在本文中首先讨论多重继承。

多重继承

例如,在现实世界的场景中,如果母亲和父亲孕育了一个孩子,这个孩子将继承父母的一切。因此,这个孩子的母亲和父亲被认为是派生类。回到多重继承的话题。在整个讨论过程中,我们将使用“构造函数”。当存在多重继承时,继承类(子类)的构造函数会按照祖先的顺序运行。然而,对于析构函数,继承顺序是相反的。我们现在将用一个简单的例子来说明继承在 C++ 中是如何工作的。

C++ 的多重继承特性允许一个类可以从多个类继承。被继承类的构造函数按照它们被继承的顺序被调用。例如,在下面的程序中,类 B 的构造函数在 A 之前被调用。

一个类可以从多个基类派生。

示例

  • FATHER 和 MOTHER 类是 CHILD 类的祖先。
  • PETROL 类源于 LIQUID 和 FUEL 类。

让我们看一个例子来更好地理解这个概念

输出

two's constructor is called here
one's constructor is called here
three's constructor is called here
?????????????????..
Process executed in 0.11 seconds
Press any key continue.

析构函数在构造函数之后以相反的顺序被调用。

菱形问题:当一个类的两个父类共享同一个基类时,就会出现菱形问题。例如,在下图中,TA 类从 Person 类接收了每个属性的两份副本,这会导致歧义。例如,思考下面的程序。

输出

Base :: Base ( int ) called
Derived :: Derived ( int ) called
Base :: Base ( int ) called
Derived_2 :: Derived_2 ( int ) called
Result :: Result ( int ) called
?????????????????..
Process executed in 0.11 seconds
Press any key continue.

说明

在上面提到的代码中,类 "Base" 被调用了两次。当对象 "rs1" 被销毁时,"Base" 的析构函数也将被调用两次。由于对象 "rs1" 包含了 "Base" 的每个元素的两个副本,导致了混淆。这个问题可以通过使用 "virtual" 关键字来解决。为了避免在 "Result" 类中出现 "Base" 的两个实例,我们将 "Derived" 和 "Derived_2" 类创建为虚基类。例如,思考下面的程序。

输出

Base :: Base ( ) is called
Derived :: Derived ( int ) is called
Derived_1 :: Derived_1 ( int ) is called
Result :: Result ( int ) is called	
?????????????????..
Process executed in 0.11 seconds
Press any key continue.

说明

在上面的程序中,对 "Person" 的构造函数只进行了一次调用。值得注意的是,在上面提到的输出中,调用的是 "Person" 的默认构造函数。即使父类显式调用了参数化构造函数,当使用 "virtual" 关键字时,默认情况下也会调用祖父类的默认构造函数。我如何使用 'Person' 类的参数化构造函数呢?必须在 "TA" 类中调用该构造函数。以下面的软件为例。

输出

Base :: Base ( int ) is called
Derived :: Derived ( int ) is called
Derived_1 :: Derived_1 ( int ) is called
Result :: Result ( int ) is called
?????????????????..
Process executed in 0.11 seconds
Press any key continue.

说明

祖父类的构造函数通常必须通过父类而不是直接调用。只有在使用 "virtual" 关键字时才允许直接调用。


下一个主题C++ 中的函数原型