Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++';实现了什么样的多重继承?_C++_Inheritance_Compiler Construction_Multiple Inheritance_Language Implementation - Fatal编程技术网

C++ C++';实现了什么样的多重继承?

C++ C++';实现了什么样的多重继承?,c++,inheritance,compiler-construction,multiple-inheritance,language-implementation,C++,Inheritance,Compiler Construction,Multiple Inheritance,Language Implementation,单一继承易于实现。例如,在C中,继承可以模拟为: struct Base { int a; } struct Descendant { Base parent; int b; } 但是对于多重继承,编译器必须在新构造的类中安排多个父类。怎么做的 我看到出现的问题是:父母应该被安排在AB或BA,或者甚至其他方式?然后,如果我做一个演员: SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents; Se

单一继承易于实现。例如,在C中,继承可以模拟为:

struct Base { int a; }
struct Descendant { Base parent; int b; }
但是对于多重继承,编译器必须在新构造的类中安排多个父类。怎么做的

我看到出现的问题是:父母应该被安排在AB或BA,或者甚至其他方式?然后,如果我做一个演员:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;
SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;

编译器必须考虑是否更改原始指针。虚拟现实也需要类似的技巧。

关于它是如何在VC++中实现的,这完全取决于编译器是如何实现的,但我认为它一般是通过VTHeS的一个非结构化的结构来完成的。

< P>以下C++的创建者描述了一个可能的多重继承的实现:


-Bjarne Stroustrup

父母按指定顺序排列:

class Derived : A, B {} // A comes first, then B

class Derived : B, A {} // B comes first, then A

第二种情况是以特定于编译器的方式处理的。一种常见的方法是使用指针大于平台指针大小的指针来存储额外的数据。

< P>这是一个真正不是C++特定的有趣问题。当您有一种具有多重分派和多重继承(例如CLOS)的语言时,事情也会变得更加复杂

人们已经注意到有不同的方法来解决这个问题。在本文中,您可能会发现阅读一些关于元对象协议(MOP)的内容很有趣

然后,如果我做一个演员:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;
SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;

编译器必须考虑是否更改原始指针。与虚拟人类似的棘手问题

对于非虚拟继承,这没有您想象的那么复杂-在编译cast时,编译器知道派生类的确切布局(毕竟,编译器完成了布局)。通常情况下,只需从派生类指针中添加/减去一个固定的偏移量(对于其中一个基类,该偏移量可能为零)

对于虚拟继承,它可能更复杂一点——它可能涉及从vtbl(或类似)获取偏移量


斯坦·利普曼(Stan Lippman)的书很好地描述了这种东西可能(而且经常是)如何工作。

我做了一个简单的实验:

class BaseA { int a; };
class BaseB { int b; };
class Descendant : public BaseA, BaseB {};
int main() {
        Descendant d;
        BaseB * b = (BaseB*) &d;
        Descendant *d2 = (Descendant *) b;
        printf("Descendant: %p, casted BaseB: %p, casted back Descendant: %p\n", &d, b, d2);
}
输出为:

Descendant: 0xbfc0e3e0, casted BaseB: 0xbfc0e3e4, casted back Descendant: 0xbfc0e3e0

很好地认识到,静态铸造并不总是意味着“在不接触内容的情况下更改类型”。(好吧,当数据类型彼此不匹配时,内容也会受到干扰,但我认为情况不同)。

C模拟会忘记VTable(实现细节)指针:@达里奥:本文讨论多重继承中的过载问题,但不包含任何关于C++中对象布局和对象的转换。@ Martin York:如果类中没有虚拟方法,则没有V表指针。这很常见,但我不认为是必需的。我已经看到了另一种方法。这完全取决于实现。顺序只影响构造函数调用的顺序。但具体布局尚未确定。我之前做过测试,GCC将空基放在内存中的第一位,以利用空基类优化。我认为如果语言不支持指向引用对象的“原始”指针,并且没有向后兼容性,那么实现起来就容易多了。因为如果他们这样做,指向对象的指针的转换是非常棘手的。一种语言可以在引用类和类实例中添加任意多的元信息。在C++中,这是不容易完成的。替换链接:在阅读这两个之后,取决于你所追求的内容。这(斯特劳斯特鲁普的一篇)非常详细,涵盖了理论。下面由Nemanja提出的一个(MSDN的一个)更简单,并且涵盖了一个真正的实现。这两个链接现在都死了,但对我来说是有效的。