类中'virtual'的含义

Meaning of 'virtual' in classes

本文关键字:virtual 类中      更新时间:2023-10-16

在以下情况下,virtual用于解决菱形问题,使类 A 的子对象与 B 和 C 共享。

例如:

class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public B, public C { };

这种类型的继承将在编译时还是运行时解析?我的意思是,当用于函数和类时,虚拟的含义有多大不同?当使用虚拟从基类继承时,是否有动态绑定的概念?

继承不必

像你所说的那样"解决",所以这个问题不是很清楚。

重要的区别在于普通继承和虚拟继承。如果您通常继承,即 B : AC : A,则类D : B, C有两个类型A的子类,即D::B::AD::C::A。另一方面,如果BC实际上继承自A,那么最终的子类组合将被推迟到你定义最终类型。也就是说,B : virtual AC : virtual A自己都有一个虚拟子类A如果你要实例化BC,它就会变成现实。另一方面,如果进一步从类派生,则派生最多的类将仅包含一个类型为 A 的子类。

也许您可能想考虑与成员函数的类比。如果每个派生类都添加与基函数同名的成员函数,则最终会得到几个不同的函数。另一方面,如果基函数是virtual,那么你只有一个函数,它在派生最多的类中定义。每个中间类中仍然有某种函数(假设该函数不是纯虚拟的(,但只有最后一个类定义了"活动"定义。

虚拟

继承对构造函数有影响,即虚拟基构造函数(即 A()在示例中(由派生最多的类直接调用,即 D而不是BC。如果你愿意,这是因为只有D"知道"它只包含一个A子类,所以它直接"负责"。 BC只是持有一个虚拟占位符,让位于最终的、最派生的类。

通过任何基指针/引用访问成员函数的行为与预期一样,并以通常的方式(即动态,通常(解析,但这与虚拟继承无关。实际的函数查找可能有点复杂,因为它可能涉及额外的间接级别,但这不会改变任何基本内容。

虚拟继承在运行时解析。

虚拟继承,就像虚函数一样,意味着类的每个实例都可以访问描述虚拟事物在哪里可以找到运行时数据。

在 如何在编译器中实现虚拟继承C++很好地描述了失败?

这种类型的继承将在编译时还是运行时解析?

继承定义类型的形状(内存占用(,并且始终在编译时解析。另一方面,对基类型成员的访问将在运行时解析,原因是层次结构中的中间类型无法知道基子对象将在最派生的类型中放置在内存中的什么位置。

我的意思是,当用于函数和类时,虚拟的含义有多大不同?

各个级别的类型和功能都不同,所以这里没有太多要说的。唯一的共同点是,有一部分工作在编译时无法完全解决。特别是,相似之处在于使用虚函数的代码依赖于 vptr(虚拟表指针(来为派生最多的类型找到合适的 vtable(虚拟表(,并且以类似的方式,访问基对象需要使用存储在虚拟派生自基类型的每个子对象的指针。

您可以在 Itanium C++ ABI 中阅读更多内容(关于特定实现,所有这些都不是标准的一部分(,特别是在非 POD 类类型中。

作为简短的总结,每当类型 D 虚拟继承自类型 B 时,D 子对象将包含指向 B 子对象的隐藏指针。对该指针的需求源于这样一个事实,即 B 子对象相对于 D 的相对位置可以随着进一步继承而改变。

我的理解是虚拟类解决了编译时的歧义。 例如,假设 B 和 C 都有一个 getSize 方法。

如果没有 virtual,对 D.getSize 的调用将尝试使用基类 getSize 方法。 由于 B 和 C 都有一个 getSize 方法,因此编译器无法正确解决歧义,并且代码将无法编译。

对于 virtual,对 D.getSize 的调用使用 deedent getSize 方法,允许代码正确编译。