C的多重继承是如何实现的?

发布于 2024-07-24 06:44:13 字数 379 浏览 9 评论 0原文

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

struct Base { int a; }
struct Descendant { Base parent; int b; }

但对于多重继承,编译器必须在新构造的类中安排多个父类。 它是如何完成的?

我看到出现的问题是:父母应该被安排在AB还是BA,或者甚至其他方式? 然后,如果我进行强制转换:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;

编译器必须考虑是否更改原始指针。 虚拟也需要类似的棘手事情。

Single inheritance is easy to implement. For example, in C, the inheritance can be simulated as:

struct Base { int a; }
struct Descendant { Base parent; int b; }

But with multiple inheritance, the compiler has to arrange multiple parents inside newly constructed class. How is it done?

The problem I see arising is: should the parents be arranged in AB or BA, or maybe even other way? And then, if I do a cast:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;

The compiler must consider whether to alter or not the original pointer. Similar tricky things are required with virtuals.

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

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

发布评论

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

评论(7

記憶穿過時間隧道 2024-07-31 06:44:13

C++ 创建者的以下论文描述了多重继承的可能实现:

C++ 的多重继承 - Bjarne Stroustrup

The following paper from the creator of C++ describes a possible implementation of multiple inheritance:

Multiple Inheritance for C++ - Bjarne Stroustrup

回眸一遍 2024-07-31 06:44:13

这篇相当老的 MSDN 文章介绍了如何在 VC++ 中实现它。

There was this pretty old MSDN article on how it was implemented in VC++.

老旧海报 2024-07-31 06:44:13

然后,如果我进行转换:

SecondBase base = (SecondBase *) object_with_base1_and_base2_parents; 
  

编译器必须考虑是否改变原始指针。 与虚拟类似的棘手事情。

对于非虚拟继承,这没有您想象的那么棘手 - 在编译强制转换时,编译器知道派生类的确切布局(毕竟,编译器进行了布局)。 通常发生的只是从派生类指针中添加/减去一个固定偏移量(对于基类之一可能为零)。

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

Stan Lippman 的书 “C++ 对象模型内部” 对这些东西可能(并且通常实际上)如何工作。

And then, if I do a cast:

SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;

The compiler must consider whether to alter or not the original pointer. Similar tricky things with virtuals.

With non-virutal inheritance this is less tricky than you might think - at the point where the cast is compiled, the compiler knows the exact layout of the derived class (after all, the compiler did the layout). Usually all that happens is a fixed offset (which may be zero for one of the base classes) is added/subtracted from the derived class pointer.

With virutal inheritance it is maybe a bit more complex - it may involve grabbing an offset from a vtbl (or similar).

Stan Lippman's book, "Inside the C++ Object Model" has very good descriptions of how this stuff might (and often actually does) work.

十六岁半 2024-07-31 06:44:13

父级按指定的顺序排列:

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

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

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

Parents are arranged in the order that they're specified:

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

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

Your second case is handled in a compiler-specific manner. One common method is using pointers that are larger than the platform's pointer size, to store extra data.

扛起拖把扫天下 2024-07-31 06:44:13

这是一个有趣的问题,实际上并不是 C++ 特有的。 当您使用具有多重分派和多重继承的语言(例如 CLOS)时,事情也会变得更加复杂。

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

This is an interesting issue that really isn't C++ specific. Things get more complex also when you have a language with multiple dispatch as well as multiple inheritance (e.g. CLOS).

People have already noted that there are different ways to approach the problem. You might find reading a bit about Meta-Object Protocols (MOPs) interesting in this context...

烟酒忠诚 2024-07-31 06:44:13

它完全取决于编译器如何完成,但我相信它通常通过 vtable 的层次结构完成。

Its entirely down to the compiler how it is done, but I beleive its generally done througha heirarchical structure of vtables.

静待花开 2024-07-31 06:44:13

我进行了简单的实验:

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

很高兴认识到静态转换并不总是意味着“更改类型而不触及内容”。 (好吧,当数据类型彼此不适合时,也会对内容产生干扰,但在我看来这是不同的情况)。

I have performed simple experiment:

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

Output is:

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

It's good to realise that static casting does not always mean "change the type without touching the content". (Well, when data types do not fit each other, then there will be also an interference into content, but it's different situation IMO).

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