深入解析C++编程中基类与基类的继承的相关知识

2020-01-06 14:30:05王冬梅

深入解析C++编程中基类与基类的继承的相关知识

同一个类的虚拟组件与非虚拟组件
在图中,CashierQueue 和 LunchQueue 将 Queue 用作虚拟基类。但是,TakeoutQueue 将 Queue 指定为基类而不是虚拟基类。因此,LunchTakeoutCashierQueue 具有类型 Queue 的两个子对象:一个来自包含 LunchCashierQueue 的继承路径,另一个来自包含 TakeoutQueue 的路径。下图对此进行了演示。

深入解析C++编程中基类与基类的继承的相关知识

带虚拟和非虚拟继承的对象布局
注意
与非虚拟继承相比较,虚拟继承提供了显著的大小优势。但是,它可能会引入额外的处理开销。
如果派生类重写它从虚拟基类继承的虚函数,并且派生基类的构造函数或析构函数使用指向虚拟基类的指针调用该虚函数,则编译器可能会将其他隐藏的“vtordisp”字段引入到具有虚拟基的类中。/vd0 编译器选项将禁止添加隐藏的 vtordisp 构造函数/析构函数置换成员。默认的 /vd1 编译器选项会在必要时启用它们。仅当确定所有类构造函数和析构函数以虚拟方式调用虚函数时才关闭 vtordisps。
/vd 编译器选项会影响整个编译模块。使用 vtordisp 杂注可以逐个类地禁用 vtordisp 字段,然后重新启用这些字段:


#pragma vtordisp( off )
class GetReal : virtual public { ... };
#pragma vtordisp( on )

对于前面的类声明,如下所示的代码是不明确的,因为 b 所指的 b 是在 A 中还是在 B 中并不清楚:


C *pc = new C;

pc->b();

名称多义性
多重继承使得沿多个路径继承名称成为可能。沿这些路径的类成员名称不一定是唯一的。这些名称冲突称为“多义性”。
任何引用类成员的表达式必须采用明确的引用。以下示例说明如何产生多义性:


// deriv_NameAmbiguities.cpp
// compile with: /LD
// Declare two base classes, A and B.
class A {
public:
 unsigned a;
 unsigned b();
};

class B {
public:
 unsigned a(); // Note that class A also has a member "a"
 int b();  // and a member "b".
 char c;
};

// Define class C as derived from A and B.
class C : public A, public B {};