基类的填充会被复制到派生类中吗?

2023-12-21

最近,我一直在阅读《C++对象模型内部》。它表示,如果您想将基类分配给派生类,基类中使用的填充也应该复制到派生类中。于是,我在64位电脑下运行测试:

    class A {
    public:
        int valA;
        char a;
    };
    class B : public A {
    public:
        char b;
    };
    class C : public B {
    public:
        char c;
    };
    int main(){
        std::cout << sizeof(A) << " " << sizeof(B) << " " << sizeof(C) 
        << std::endl;
        C c;
        printf("%p\n%p\n%p\n",&c,&c.b,&c.c);
    }

结果如下:

    8 12 12

    0x7ffd22c5072c

    0x7ffd22c50734

    0x7ffd22c50735

那么为什么C与B大小相同呢?虽然看起来B在A中使用了3字节填充。


那么为什么C与B大小相同呢?

因为尾部填充B被重复用于C::b。填充物可以重复使用,因为B不是 POD(普通旧数据)类(因为它不是标准布局类)。

虽然看起来B在A中使用了3字节填充。

的填充A不能被其他子对象重用B, 因为A是一个标准布局类,并且可以轻松复制,即A是一个 POD 类。


基类的填充会被复制到派生类中吗?

我想您并不是想问有关复制的问题,而是想问派生类的基类子对象是否具有与单个类型相同的填充。

答案是,从上面可以推断出:填充将是相同的,除了尾部填充可以被其他子对象重复使用,除非基类是 POD,在这种情况下其填充不能被重复使用。

对于填充是否可以重用的情况,标准中并没有规定,并且编译器之间也存在差异。


请解释或链接到“标准布局类型”的定义。

目前的标准草案:

[基本类型]

...标量类型、标准布局类类型 ([class.prop])、此类类型的数组以及这些类型的 cv 限定版本统称为标准布局类型。


[class.prop](在旧版本的标准中,这些可以直接在[class]下找到)

如果满足以下条件,S 类就是标准布局类:

  • (3.1) 没有非标准布局类类型(或此类类型的数组)或引用的非静态数据成员,

  • (3.2) 没有虚函数,也没有虚基类,

  • (3.3) 对所有非静态数据成员具有相同的访问控制,

  • (3.4) 没有非标准布局基类,

  • (3.5) 至多有一个任意给定类型的基类子对象,

  • (3.6) 类及其基类中的所有非静态数据成员和位域首先在同一个类中声明,并且

  • (3.7) 没有类型集合 M(S) 的元素作为基类,其中对于任何类型 X,M(X) 定义如下。107 [ 注:M(X) 是 可能位于某个位置的所有非基类子对象的类型集 X 中的零偏移。— 尾注]

    • (3.7.1) 如果 X 是没有(可能继承的)非静态数据成员的非联合类类型,则集合 M(X) 为空。

    • (3.7.2) 如果 X 是非联合类类型,具有类型 X0 的非静态数据成员,该成员的大小为零或者是第一个 X 的非静态数据成员(其中所述成员可以是匿名的) union),集合 M(X) 由 X0 和 M(X0) 的元素组成。

    • (3.7.3) 如果 X 是联合类型,则集合 M(X) 是所有 M(Ui) 和包含所有 Ui 的集合的并集,其中每个 Ui 是该集合的类型 X 的第 i 个非静态数据成员。

    • (3.7.4) 如果 X 是元素类型为 Xe 的数组类型,则集合 M(X) 由 Xe 和 M(Xe) 的元素组成。

    • (3.7.5) 如果 X 是非类、非数组类型,则集合 M(X) 为空。

第(3.6)条适用于这种情况。 B 的某些成员不是首先在 B 中声明的。特别是,B::A::valA 和 B::A::a 首先在 A 中声明。描述规则的更友好的方式是:该类必须具有没有直接成员,或者其祖先都必须没有成员。在这种情况下,基类和派生类都有成员,因此它不是标准布局。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基类的填充会被复制到派生类中吗? 的相关文章

随机推荐