我正在阅读-- 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。我称它们为“不使用填充”方式和“使用填充”方式简称。
为了解释为什么不使用填充部分,本书给出了以下代码:
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指向的pc2_2对象将被复制到pc1_1指向的Concrete3 2/Concrete3 3对象的Concrete1子对象中。这本书还说它是一个“成员级”副本,但看起来更像一个“对象”副本,因为它意味着填充部分也会被复制。
书中以“使用填充”的方式表示,它将覆盖bit2成员,因为*pc2_2的对应字节是一个填充字节。再一次,我用gcc 4.4.7试了一下,结果发现bit2成员没有被覆盖。因此,我猜想这个副本是一个真正的“成员级”拷贝,只有val和bit1被复制。
因此,我的问题是: 1. gcc的活动是否正确:“使用填充”的方式和真实的“成员级”复制? 2.基类的私有成员不能在派生类中访问,但派生类对象包含其基类子对象(val和bit1)中的所有私有成员。为什么它被设计成包含基类私有成员,即使它们甚至不能在派生类对象中被访问?仅用于复制操作,如*pc1_1 = *pc2_2;
谢谢
发布于 2016-02-19 04:48:09
关于你的第一个问题:
我试图用不同的编译器复制您在ideone.com上描述为“使用填充”的行为,但失败了。Clang,gcc 4.3和gcc 5.1似乎没有使用基类的衬垫。但是从这个问题的答案可以看出gcc确实利用了这个填充物。
该标准引入了荚型的概念,但它明确声明
9类 班级 7 A类S是一个标准布局类,如果它:(.) (7.6)类及其基类中的所有非静态数据成员和位字段首先在同一个类(.)中声明。
因此,这不适用于您的类,因为基类和派生类中都有数据成员。我找不到任何关于非POD-类型需要如何布局的参考资料。相关问题的答案之一是,这是一个变化的主题。
继承的重要之处在于--使用指针或引用--您可以像使用基类的对象一样使用派生对象。这意味着您可以像使用Concrete3*一样使用Concrete1*。但是这是独立的,您是否使用填充,只要在添加Concrete2和Concrete3的数据成员时不更改Concrete3的布局。
关于你的第二个问题:
标准规定如下:
11成员访问控制 class.access 1一个类的成员可以是
如您所见,它只指定可以使用名称的位置。例如,您仍然可以将引用或指针返回给私有成员。这意味着它们必须存在于记忆中的某个地方。事实上,对象的状态是由其成员的状态定义的--私有或公共状态只是代码中允许您直接访问它们的位置的问题。
https://stackoverflow.com/questions/35496609
复制相似问题