编译器内部如何解决C++中的钻石问题?

发布于 2024-12-03 23:51:31 字数 545 浏览 2 评论 0原文

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

例如:

   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();
   }

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

We know that we can solve the diamond problem using virtual inheritance.

For example:

   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();
   }

When we compile this code we will get an ambiguity error.
Now my question is how compiler internally detects this ambiguity problem (diamond problem).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

抹茶夏天i‖ 2024-12-10 23:51:31

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

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

The compiler builds tables that list all the members of every class, and also has links that allow it to go up and down the inheritance chain for any class.

When it needs to locate a member variable (weight in your example) the compiler starts from the actual class, in your case Liger. It won't find a weight member there, so it then moves one level up to the parent class(es). In this case there are two, so it scans both Tiger and Lion for a member of name weight. There aren't still any hits, so now it needs to go up one more level, but it needs to do it twice, once for each class at this level. This continues until the required member is found at some level of the inheritance tree. If at any given level it finds only one member considering all the multiple inheritance branches everything is good, if it finds two or more members with the required name then it cannot decide which one to pick so it errors.

蓝咒 2024-12-10 23:51:31

当编译器为类创建函数指针表时,每个符号必须在其中出现一次。在此示例中,getWeight 出现了两次:在 Tiger 中和在 Lion 中(因为 Liger 没有实现它,所以它会沿着树向上寻找它),因此编译器会被卡住。

实际上,这很简单。

When compiler creates a table of function pointers for a class, every symbol must appear in it exactly once. In this example, getWeight appears twice: in Tiger and in Lion (because Liger doesn't implement it, so it goes up the tree to look for it), thus the compiler gets stuck.

It's pretty simple, actually.

辞别 2024-12-10 23:51:31

在您的代码中,liger 的结构是

Liger[Tiger[Animal]Lion[Animal]]

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

)继承将生成一个类似于 There is now just one Animal 的结构

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

,可以从两个基础间接访问,因此从 Liger 到 Animal 的转换不再含糊不清。

With your code, the structure for liger is

Liger[Tiger[Animal]Lion[Animal]]

If you call an Animal function from a Liger pointer, there are actually two Animal a Liger can convert to (hence the ambiguity)

Virtual inheritance will generate a structure like

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

There is now just one Animal, indirectly reachable from both of the bases, so a conversion from Liger to Animal is anymore ambiguous.

错々过的事 2024-12-10 23:51:31

编译器不会检测到歧义问题。编译器只对代码中使用的内容的声明感兴趣。如果一个元素被声明多次,编译器不会抱怨。

歧义问题来自链接器。链接器在对象 lg 的继承树中看到 getWeight() 函数的两个定义,并且不知道选择哪个定义来与调用 lg.getWeight() 链接。这就是歧义所在。

the compiler does not detect the ambiguity problem. the compiler is only interested in the declarations of what is being used in the code. the compiler does not complain if an element is declared more than once.

the ambiguity problem comes from the linker. the linker sees two definitions of the getWeight() function within the inheritance tree of the object lg, and does not know which definition to choose to link with the call lg.getWeight(). so that's the ambiguity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文