菱形多态继承:sizeof 最派生类

发布于 2024-10-28 21:29:21 字数 1370 浏览 1 评论 0原文

我知道菱形继承会导致歧义,可以通过通过虚拟基类使用继承来避免它,问题不在于它。问题是当类是多态时,菱形层次结构中最派生的类的大小。这是示例代码和示例输出:

#include<iostream>

using namespace std;

class Base
{
    public:
        virtual void doSomething(){}  
};

class Derived1:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived2:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived3:public Derived1,public Derived2
{
    public:
       virtual void doSomething(){}
};

int main()
{
    Base obj;
    Derived1 objDerived1;
    Derived2 objDerived2;
    Derived3 objDerived3;

    cout<<"\n Size of Base: "<<sizeof(obj);
    cout<<"\n Size of Derived1: "<<sizeof(objDerived1);
    cout<<"\n Size of Derived2: "<<sizeof(objDerived2);
    cout<<"\n Size of Derived3: "<<sizeof(objDerived3);

    return 0;
}

我得到的输出是:

 Size of Base: 4
 Size of Derived1: 4
 Size of Derived2: 4
 Size of Derived3: 8

据我了解 Base 包含一个虚拟成员函数,因此,
sizeof Base = size of vptr = 4 在此环境中

类似的情况 Derived1 & Derived2 类。

以下是我与上述场景相关的问题:
Derived3 类对象的大小怎么样,这是否意味着 Derived3 类有 2 个 vptr?
Derived3 类如何与这 2 个 vptr 一起工作,关于它使用的机制有什么想法吗?
类的大小保留为编译器和类的实现细节。不是由标准定义的(因为虚拟机制本身就是编译器的实现细节)?

I understand that the Diamond shaped inheritance causes ambiguity and it can be avoided by using inheritance through virtual Base Classes, the question is not about it. The question is about sizeof the most derived class in a diamond shaped hierarchy when the classes are polymorphic. Here is a sample code and the sample output:

#include<iostream>

using namespace std;

class Base
{
    public:
        virtual void doSomething(){}  
};

class Derived1:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived2:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived3:public Derived1,public Derived2
{
    public:
       virtual void doSomething(){}
};

int main()
{
    Base obj;
    Derived1 objDerived1;
    Derived2 objDerived2;
    Derived3 objDerived3;

    cout<<"\n Size of Base: "<<sizeof(obj);
    cout<<"\n Size of Derived1: "<<sizeof(objDerived1);
    cout<<"\n Size of Derived2: "<<sizeof(objDerived2);
    cout<<"\n Size of Derived3: "<<sizeof(objDerived3);

    return 0;
}

The output i get is:

 Size of Base: 4
 Size of Derived1: 4
 Size of Derived2: 4
 Size of Derived3: 8

As I understand Base contains a virtual member function and hence,
sizeof Base = size of vptr = 4 on this environment

Similar is the case Derived1 & Derived2 classes.

Here are my questions related to above scenario:
How about size of a Derived3 class object, Does it mean Derived3 class has 2 vptr?
How does the Derived3 class work with these 2 vptr, Any ideas about the mechanism it uses?
The sizeof classes is left as implementation detail of compiler & not defined by the Standard(as the virtual mechanism itself is an implementation detail of compilers)?

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

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

发布评论

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

评论(4

乞讨 2024-11-04 21:29:21

是的,Derived3 有两个 vtable 指针。如果您按值访问它,它会使用 Derived3 版本,或者从父级中选择一个函数,或者如果无法决定则表示它是不明确的。

对于子级,它使用与多态使用的父级 1/2 相对应的 vtable。

请注意,您没有正确使用虚拟继承:我相信 Derived1 和 2 应该从 Base 虚拟继承。 sizeof(Derived3) 似乎仍然是 8,因为它仍然有两个可能的父级可以被视为 Derived3。当你转换为父对象之一时,编译器实际上会调整对象指针以获得正确的虚函数表。

另外我应该指出,任何与 vtable 相关的内容都是特定于实现的,因为标准中甚至没有提及 vtable。

Yes, Derived3 has two vtable pointers. If you're accessing it by value, it uses the Derived3 version, or picks a function from a parent, or denotes that it's ambiguous if it can't decide.

In the case of a child, it uses the vtable corresponding to the parent 1/2 that's being used polymorphically.

Note that you didn't use virtual inheritance correctly: I believe Derived1 and 2 should inherit virtually from Base. sizeof(Derived3) still seems to be 8, because it still has two possible parents that could be treated as a Derived3. When you cast up to one of the parents the compiler will actually adjust the object pointer to have the correct vtable.

Also I should point out that anything vtable-related is implementation specific because there isn't even any mention of vtables in the standard.

美羊羊 2024-11-04 21:29:21

对代码的一个小修复:虚拟应该位于导出 2 和导出 3 的定义中才能工作。

http://www.parashift.com/c++-faq -lite/multiple-inheritance.html#faq-25.9

A small fix to your code: the virtual is supposed to be in the definition of derived2 and derived 3 in order to work.

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

就是爱搞怪 2024-11-04 21:29:21

我认为您想知道一些完全特定于实现的东西。
您不应该对班级的规模做出任何假设。

编辑:虽然好奇是一种已被证明的品质;-)

I think you are wondering about something that is totally implementation specific.
You should not assume anything about the size of the classes.

Edit: though being curious is a proven quality ;-)

温馨耳语 2024-11-04 21:29:21

考虑一个稍微不同的情况:

struct B { virtual void f(); };
struct L : virtual B { virtual void g(); };
struct R : virtual B { virtual void h(); };
struct D : L, R {};

在典型的实现中,L::g 将处于相同的位置(比如在
L 的 vtable 中的索引 0) 相当于 R 的 vtable 中的 R:h。现在考虑会发生什么
给出以下代码:

D* pd = new D;
L* pl = pd;
R* pr = pd;
pl->g();
pr->h();

在最后两行中,编译器将生成代码来查找
vtable 中同一位置的函数地址。所以
通过 pl 访问的 vtable 不能与该 vtable (或前缀相同)
一个)通过 pr 访问。因此,完整的对象至少需要
两个vptr,指向两个不同的vtable。

Consider a slightly different case:

struct B { virtual void f(); };
struct L : virtual B { virtual void g(); };
struct R : virtual B { virtual void h(); };
struct D : L, R {};

In a typical implementation, L::g will be in the same position (say at
index 0) in L's vtable as R:h in R's vtable. Now consider what happens
given the following code:

D* pd = new D;
L* pl = pd;
R* pr = pd;
pl->g();
pr->h();

In the last two lines, the compiler will generate code to find the
address of the function at the same position in the vtable. So the
vtable accessed through pl cannot be the same as the one (or a prefix of
the one) accessed through pr. Thus, the complete object needs at least
two vptr, to point to two different vtable.

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