首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gcc 4.4.7的C++对象模型:派生类对象中的基类子对象填充

gcc 4.4.7的C++对象模型:派生类对象中的基类子对象填充
EN

Stack Overflow用户
提问于 2016-02-19 03:08:51
回答 1查看 233关注 0票数 2

我正在阅读-- 3.4继承和数据成员。它说:“语言保证基类子对象在派生类中的完整性。”此外,它还举例如下:

代码语言:javascript
复制
class Concrete1
{
private:
    int val;
    char bit1;
};

class Concrete2 : public Concrete1
{
private:
    char bit2;
};

class Concrete3 : public Concrete2
{
private:
    char bit3;
};

Concrete1对象模型是:

代码语言:javascript
复制
4 bytes for val, 
1 byte for bit1,
3 bytes padding. 
// 8 bytes in total.

Concrete2对象模型是:

代码语言:javascript
复制
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。我称它们为“不使用填充”方式和“使用填充”方式简称。

为了解释为什么不使用填充部分,本书给出了以下代码:

代码语言:javascript
复制
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;

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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*。但是这是独立的,您是否使用填充,只要在添加Concrete2Concrete3的数据成员时不更改Concrete3的布局。

关于你的第二个问题:

标准规定如下:

11成员访问控制 class.access 1一个类的成员可以是

  • (1.1)私人名称;即该名称只可供其所属类别的成员及朋友使用。
  • (1.2)受保护的;即其名称只可由其所属类别的成员及朋友使用,由该类别衍生的类别及其朋友使用(见11.4)。
  • (1.3)公开的;也就是说,它的名称可以在任何地方使用,不受访问限制。

如您所见,它只指定可以使用名称的位置。例如,您仍然可以将引用或指针返回给私有成员。这意味着它们必须存在于记忆中的某个地方。事实上,对象的状态是由其成员的状态定义的--私有或公共状态只是代码中允许您直接访问它们的位置的问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35496609

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档