最近,我一直在阅读《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(使用前将#替换为@)