《深度探索C++对象模型》第一章 | 关于对象

C++对象模式

非静态数据成员放置在每个类对象内,静态数据成员则被放置在所有类对象之外。静态和非静态的成员函数也被放置在所有类对象之外。每个类产生一堆指向虚函数的指针,放在虚表(vtbl)中。每个类对象维护一个指针(vptr),指向相关的虚表。虚表的首元素维护了每个类所关联的type_info对象。
优点:空间与存取时间效率高
缺点:一旦所用到的类对象的非静态数据成员有所修改,那么代码就要重新编译

加上继承

C++支持单一继承、多重继承和虚拟继承。在虚拟继承的情况下,基类不管在继承链中被派生多少次,永远只会存在一个实体。

C++中凡是处于同一个访问控制修饰符下的数据,必定保证以其生命的次序出现在内存布局中。然而被放置在多个访问控制修饰符下的各笔数据,内存的排布顺序就不一定了。同样的道理,基类和派生类的内存布局也没有谁先谁后的强制规定。虚函数也会对内存布局产生影响。

对象的差异

只有通过指针或者引用间接处理基类对象,才能支持面向对象程序设计所需的多态性质。

C++以下列方法支持多态:

  • 经由一组隐含的转化操作,例如把一个派生类指针转化为一个基类的指针
  • 经由虚函数机制
  • 经由dynamic_casttypeid运算符

类对象的内存

  • 其非静态数据成员的总和
  • 加上任何由于内存对齐而填补的空间
  • 加上为了支持虚函数而内部产生的额外负担

void*类型的指针只表示一个地址,不能够通过它操作所指的对象。类型转换其实是一种编译器指令,大部分情况下它不改变一个指针所含的真正地址,只影响“被指向的内存大小和其内容”的解释方式。

加上多态之后

class Bear : public ZooAnimal{
public:
    Bear();
    ~Bear();
    // ...
    void rotate();
    virtual void dance();
    // ...
protected:
    enum Dances { ... };

    Dances dances_known;
    int cell_block;
};

Bear b;
ZooAnimal *pz = &b;
Bear *pb = &b;

这两个指针都指向Bear对象的首个字节,差别是pb所涵盖的地址包含整个Bear对象,而pz所涵盖的地址只包含Bear对象中的ZooAnimal部分。除了ZooAnimal对象中出现的成员,不能用pz直接处理Bear的任何成员,除非使用虚函数机制:

pz->cell_block;                       // 不合法
((Bear*)pz)->cell_block;              // 合法
dynamic_cast<Bear*>(pz)->cell_block;  // 合法
pb->cell_block;                       // 合法

当我们写下代码pz->rotate();时,pz的类型将在编译期决定以下两点:

  • 固定的可用接口,即pz只能调用ZooAnimalpublic接口
  • 该接口的访问权限

执行期pz所指的对象类型可以决定rotate()所调用的实体(即动态绑定)。类型信息的封装并不维护于pz中,而是维护于对象的虚函数指针和该指针所指的虚表之间

对于下面这种情况,为什么rotate()所调用的是ZooAnimal实体而不是Bear实体呢?此外,如果初始化函数(赋值操作)将一个对象的内容完整地拷贝到另一个对象中,为什么za的虚指针不指向Bear的虚表呢?

Bear b;
ZooAnimal za = b; // 会引起切割

// 调用 ZooAnimal::rotate()
za.rotate();

因为za本身是一个ZooAnimal对象而非Bear对象,所以它并不能调用Bear类型的方法。当一个基类对象被指定为派生类对象时,派生类就会被切割,以塞入较小的基类对象的内存中。因此,该基类对象就不能访问派生类的成员。而指针或者引用之所以支持多态,是因为它们不会引发内存中任何“与类型有关的内存委托操作”,改变的只是它们所指向的内存的“大小和内容解释方式”而已。
对于第二个问题,编译器在初始化和赋值操作之间做出了仲裁。编译器必须确保如果某个对象含有一个或一个以上的虚指针,那些虚指针的内容不会被基类对象初始化或改变。

原文链接: https://www.cnblogs.com/shuo-ouyang/p/12532374.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    《深度探索C++对象模型》第一章 | 关于对象

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/336466

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午10:39
下一篇 2023年3月1日 下午10:39

相关推荐