【发布时间】:2016-05-31 12:18:34
【问题描述】:
我正在阅读——3.4 继承和数据成员。它说“派生类中基类子对象完整性的语言保证”。还举了一个例子:
class Concrete1
{
private:
int val;
char bit1;
};
class Concrete2 : public Concrete1
{
private:
char bit2;
};
class Concrete3 : public Concrete2
{
private:
char bit3;
};
Concrete1 对象模型是:
4 bytes for val,
1 byte for bit1,
3 bytes padding.
// 8 bytes in total.
Concrete2 对象模型是:
8 bytes for Concrete1 subobject,
1 byte for bit2,
3 bytes padding.
// 12 bytes in total.
同样,Concrete3 对象模型是 16 字节。
Concrete2 对象成员 bit2 不使用 Concrete1 子对象的填充部分,所以它是 12 字节。但是当我在 gcc 4.4.7 中尝试示例时,Concrete2 对象和 Concrete3 对象与 Concrete1 对象的大小相同——8 字节。所以我猜gcc使用Concrete1对象的填充部分来存储bit2和bit3。我将它们简称为“不使用填充”方式和“使用填充”方式。
为了说明为什么不使用padding部分,书中给出如下代码:
Concrete2 *pc2;
Concrete1 *pc1_1, *pc2_2;
pc1_1 = pc2;
*pc1_1 = *pc2_2; // pc1_1 may point to a Concrete2 or Concrete3 object.
以“不使用填充”的方式,pc2_2指向的Concrete1对象将被复制到pc1_1指向的Concrete2/Concrete3对象的Concrete1子对象中。这本书还说它是一个“成员”副本,但它看起来更像是一个“对象”副本,因为它暗示填充部分也被复制了。
在“使用填充”的方式中,书上说它将覆盖 bit2 成员,因为 *pc2_2 的相应字节是填充字节。同样,我用 gcc 4.4.7 尝试过,结果发现 bit2 成员没有被覆盖。所以我猜这个副本是一个真正的“成员”副本,只是 val 和 bit1 被复制了。
所以我的问题是: 1.我对gcc活动是否正确:“使用填充”方式和真正的“会员”副本? 2.基类的私有成员不能在派生类中访问,但派生类对象在对象模型中包含其基类子对象(val和bit1)中的所有私有成员。为什么它被设计为包含基类私有成员,即使它们甚至不能在派生类对象中访问?仅适用于 *pc1_1 = *pc2_2; 之类的复制操作?
谢谢
【问题讨论】:
-
#2:通常,一个类将具有公共成员函数,而这些函数又使用私有数据成员。即使派生类无法访问其基类的私有成员,它当然也可以调用其公共方法。
-
您想阅读 C++ Itanium ABI,它描述了 gcc 使用的(部分)布局。特别说明,如果将Concrete1中的
private:替换为public:,则派生类的大小会发生变化。
标签: c++ object inheritance gcc padding