c++对象模型

  • C语言中,数据与处理数据的操作(函数)是分开声明的,这种程序方法被称为程序性的;而在c++中,则是使用abstract data type(ADT)或class hierarchy的数据封装
  • c++对于结构体和函数(不包含virtual和non-inline)的封装并没有增加布局成本,对于C++而言,在布局以及存取时间上主要的额外负担是由virtual引起
    • virtual function
    • virtual base class

The c++ Object Model

  • c++中,有两种class data members:static and nonstatic,和三种class member functions:static、non-static and virtual

  • 现有以下class声明:

    class Point
    {
    public:
        Point(float xval);
        virtual ~Point();
        
        float x() const;
        static int PointCount();
        
    protected:
        virtual ostream& print( ostream & os ) const;
        
        float _x;
        static int _point_count;
    }
    
  • 此 class 可以通过三种object models表示

A Simple Object Model

  • 一个object是一系列slots,每一个slots指向一个member,Members按其声明顺序,各被指定一个slot。每一个data member or function member都有自己的一个slot

  • 目的:尽量减低C++ complier的设计复杂度,但会损失空间和执行器的效率

    image-20221010205344716

    • 意义:应用到c++的"指向成员的指针"观念中

A Table-driven Object Model

  • 将所有members的信息抽离出来放在一个member data table 和 一个member function table中,而class则含有指向这两个table的pointer

image-20221010205907499

  • 意义:成为virtual function的一个方案

The c++ Object Model

  • 此模型从A Simple Object Model派生而来,并对内存空间和存取时间优化
  • Nonstatic data members被配置于每一个class object内,static data members、Static function members、 nonstatic function members则被存放于个别的class object外。而用virtual functions来支持此model:
    • virtual tabel(vtbl)中存放一些指向由class生成的virtual functions的pointer
    • 每个class object安插一个指针(vptr),此指针指向相关的virtual table。而vptr的setting 和 resetting都有class里的constructor、destructor、copy assignment运算符自动完成。每个class关联的type_info object(支持runtime type identification,RTTI)亦由virtual table指出,通常放于表格中的第一个slot
  • 优点:空间和存取时间效率高
  • 缺点:若应用程序本身未改变,而class内的nonstatic data members有所修改,则应用程序代码需重新编译

image-20221010211713470

  • c++支持单一继承、多重继承、虚拟继承。虚拟继承中,base class不管在继承串链中被派生多少次,永远只存在一个实例subobject

image-20221010213157966

image-20221010213212880

A Keyword Distinction

  • C++为了维护和C之间的兼容性,为此付出了很多牺牲
int (*pq) ();
  • 当语言无法区分此函数是declaration还是invocation时,需要一个超越语言范围的规则,此规则会将此函数判断为declaration
  • struct的一个合理用途:将class object某个数据做封装,达到与C的兼容的空间布局,只有composition才支持
  • template并没有兼容struct

An Object Distinction

  • c++程序设计模型支持三种programming paradigms
    • procedural model
    • abstract data type model
    • object-oriented model
  • object-oriented model中,被指定的object的真实类型在每个特定执行点前无法解析,只有通过pointer 和 reference才能完成;相反,abstract data type model中,所处理的是一个固体且单一类型的实例,真实类型早在编译时期就已定义,因此速度更快且空间排布更紧凑,但没有弹性
  • c++用三种方法支持多态:
    • 经由一组隐式转化。如把derived class pointer转化为public base type的pointer
    • 经由virtual function机制
    • 经由dynamic_cast和typeid运算符
  • 多态主要用途:由一个共同的接口影响类型封装,此接口通常被定义在抽象的base class
  • class object所需的内存大小:
    • nonstatic data members的总和大小
    • 任何由于alignment(将数值调整到某数倍数)的需求而padding的空间
    • 支持virtual产生的额外负担

The Type of a Pointer

  • "指针类型"告诉编译器如何解释目的地址中的内容和大小,这也是为什么pointer和reference支持多态
  • 我们并不知道void*指针涵盖的地址空间,因此void*的指针只含有一个地址,且不能操作所指向的object
  • cast本质上是编译器指令,它并不改变指针所含的地址,而只影响"所指内存的大小和其内容"的解释方式

Adding Polymorphism

class A
{
    public:
    	virtual action1();
    ...
}


class B : public A
{
    //以下皆为B独有
    public:
    	...
    	void rotate();
    
    protected:
    	enum action2 {...};
    	int n;
}

B b;
A* p1 = &b;
B* p2 = &b;
  • 显然,我们并不不能用p1处理A以外的members,唯一方法是通过virtual

    //以下都可行
    (static_cast<B*> (p1))->n;
    
    if( B*p3 = dynamic_cast<B*>(p1) )	//此为run-time operation,成本较高
        p3->n;
    
p1->action1()
  • p1将在编译器决定以下两点:
    • 固定的可用接口
    • 此接口的access level
B b;
A a1 = b;	//造成sliced

a1.action1();	//调用A中的
  • 为什么a1中的vptr不会指向b的virtual table?
    • 编译器需确保若object含有一个或一个以上的vptrs,这些vptrs内容不会被base class object初始化或改变
  • 为什么action1()依旧是调用的A的?
    • 多态并不适用于直接存取objects

原文链接: https://www.cnblogs.com/chenglixue/p/16785424.html

欢迎关注

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

    c++对象模型

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

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

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

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

(0)
上一篇 2023年2月4日 下午7:36
下一篇 2023年2月4日 下午7:37

相关推荐