要打电话的功能?(委托姐妹班)

Joh*_*nyy 3 c++

我刚刚在C++ FAQ Lite中读到过这个

[25.10]通过虚拟继承"委托给姐妹班"意味着什么?

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

 class Der1 : public virtual Base {
 public:
   virtual void foo();
 };

 void Der1::foo()
 { bar(); }

 class Der2 : public virtual Base {
 public:
   virtual void bar();
 };

 class Join : public Der1, public Der2 {
 public:
   ...
 };

 int main()
 {
   Join* p1 = new Join();
   Der1* p2 = p1;
   Base* p3 = p1;

   p1->foo();
   p2->foo();
   p3->foo();
 } 
Run Code Online (Sandbox Code Playgroud)

"信不信由你,当Der1 :: foo的()调用这个 - >杆(),它最终调用DER2 ::巴()是的,这是正确的:即Der1知道什么一类将提供的倍率Der1 :: foo()调用的虚函数.这种"交叉委托"可以是一种强大的技术,用于自定义多态类的行为."

我的问题是:

  1. 现场背后发生了什么.

  2. 如果我添加一个Der3(虚拟继承自Base),会发生什么?(我这里没有编译器,现在无法测试它.)

Dav*_*eas 6

现场背后发生了什么.

简单的解释是,由于继承从Base在两个虚拟Der1Der2,有最派生对象的对象的单个实例Join.在编译时,假设(这是常见的情况)虚拟表作为调度机制,在编译Der1::foo时它将bar()通过vtable 重定向调用.

现在的问题是编译器如何为每个对象生成vtable,vtable for Base将包含两个空指针,vtable for Der1将包含Der1::foo一个空指针,而vtable for Der2将包含一个空指针和Der2::bar[*]

现在,由于前一级别的虚拟继承,当编译器处理Join它时会创建一个单独的Base对象,因而单个vtable用于Basesubojbect Join.它有效地融合的虚函数表Der1,并Der2和产生包含指向一个虚函数表Der1::fooDer2::bar.

因此,代码Der1::foo将通过Joinvtable分配给最终的覆盖器,在这种情况下,最终的覆盖器位于虚拟继承层次结构的不同分支中.

如果你添加一个Der3类,并且该类定义了任何一个虚函数,那么编译器将无法干净地合并三个vtable并且会抱怨,并且有一些与多重定义方法的模糊性相关的错误(没有一个覆盖器可以被认为是最后的覆盖者).如果添加相同的方法Join,则歧义将不再是问题,因为最终的覆盖将是定义的成员函数Join,因此编译器能够生成虚拟表.

[*]大多数编译器不会在这里写空指针,而是指向将打印错误消息和terminate应用程序的通用函数的指针,允许比普通的分段错误更好的诊断.