11

我们知道我们可以使用虚拟继承来解决菱形问题。

例如:

   class Animal // base class
   {
     int weight;
     public:
     int getWeight() { return weight;};
   };
   class Tiger : public Animal { /* ... */ }; 
   class Lion : public Animal { /* ... */ };
   class Liger : public Tiger, public Lion { /* ... */ }; 
   int main()
   {
     Liger lg ;
     /*COMPILE ERROR, the code below will not get past
     any C++ compiler */
     int weight = lg.getWeight();
   }

当我们编译这段代码时,我们会得到一个歧义错误。现在我的问题是编译器如何在内部检测到这种歧义问题(菱形问题)。

4

3 回答 3

4

编译器构建的表列出了每个类的所有成员,并且还具有允许它在任何类的继承链上上下移动的链接。

当它需要找到一个成员变量(在你的例子中是 weight)时,编译器从实际的类开始,在你的例子中是 Liger。它不会在那里找到权重成员,因此它会向上移动一级到父类。在这种情况下,有两个,因此它会同时扫描 Tiger 和 Lion 以查找 name weight 的成员。仍然没有任何命中,所以现在它需要再上一个级别,但它需要做两次,这个级别每个职业一次。这一直持续到在继承树的某个级别找到所需的成员。如果在任何给定级别上,考虑到所有多重继承分支,它只找到一个成员,一切都很好,如果它找到两个或多个具有所需名称的成员,那么它无法决定选择哪一个,因此会出错。

于 2011-09-12T06:21:06.440 回答
3

当编译器为一个类创建一个函数指针表时,每个符号必须在其中恰好出现一次。在这个例子中,getWeight出现了两次:inTiger和 in Lion(因为Liger没有实现它,所以它上树去寻找它),因此编译器卡住了。

实际上,这很简单。

于 2011-09-12T06:05:24.190 回答
1

使用您的代码, liger 的结构是

Liger[Tiger[Animal]Lion[Animal]]

Animal如果您从指针调用函数Liger,则 Liger 实际上可以转换为两个 Animal(因此存在歧义)

虚拟继承将生成类似的结构

Liger[Tiger[*]Lion[Animal]]
            \-----/

现在只有一个动物,可以从两个基地间接到达,所以从 Liger 到 Animal 的转换不再模棱两可。

于 2011-09-12T07:10:20.843 回答