Object Model 对象模型
在代码层面不可见,而是出现在实现层面。
关于vptr(虚指针)和vtbl(虚表)
一个类的对象的大小,首先取决于它的数据,子类继承父类数据。子类对象含有父类成分。
当一个类有虚函数时,不管有多少个,都有且只有一个vptr(虚函数指针 4bytes)。
函数多大是不定的,继承函数是继承调用权而不是继承其内存大小,父类对象有虚函数指针,子类对象一定有。
在子类中不override的父类虚函数,可以省略。
将虚指针vptr和虚函数vfun关联起来——虚函数表vtbl
虚函数表中存放的都是虚函数地址。
C中函数调用形式:call + 对应函数地址(由编译器解析),执行至return语句回到call命令处 —— 静态绑定
虚函数:vptr->vtbl->vfun地址,不再使用call命令。—— 动态绑定
通过指针调用->指针向上转型->调用虚函数 —— 虚机制(动态绑定)
(* (p->vptr)[n])(p); 或 (* p->vptr[n])(p); 虚函数动态绑定语法的C实现
关于this pointer
设计模式 Template Method 关注虚函数用法
在C++中,所有的成员函数默认含有this pointer。通过一个对象调用成员函数,this pointer是该对象的地址。this是一个指针,this指向子类对象且会向上转型,Seralize是虚函数,因此编译器动态绑定执行Seralize。
关于Dynamic Binding
static binding:call xxx
dynamic binding:call ptr 函数指针解析 (*(this->vptr)[n])(this)
Template Method中的动态绑定,通过调用this ptr的vptr访问vtbl([n]),解析对应函数地址。
动态绑定的三个条件:
- 以指针形式调用
- 存在向上转型 upcasting
- 调用函数为虚函数
谈谈const
const member functions 常量成员函数
此时 const 只能加在成员函数后,表示该成员函数不改变该 class 的数据。当成员函数的 const 和 non-const 版本同时存在时,const object 只会调用 const 版本,non-const object 只会调用 non-const 版本。设计一个类,在构思接口时就已经决定接口的行为,从而判断是否需要操作数据,是否加 const 。const 是常量成员函数签名的一部分,因此在书写时不可省略。
关于new,delete
new相关语法
- expression new
- operator new
- array new
- placement operator new
new、delete直接使用时都是表达式(expression),表达式表义唯一且不能重载在表达式执行时,分解执行的operator new、operator delete,可以进行操作符重载。array new时,内存分配一个4byte的counter+数组整包数据。
在调用时,使用 ‘::' global scope标识符,可以绕过类中重载的设计,当然,不能绕过被重载的全局设计。
placement operator new: class member operator new(),支持写出多个版本,前提是对每一版本的声明都必须有独特的参数列。其中第一个参数必须是 size_t,其余参数以new指定的 placemnet arguments 为初值。出现于 new (...) 中 ... 位置的就是 placement arguments。同样的,我们可以不对应的重载class member operator delete(),但它们绝不会被 delete 调用。只有当 new 所调用的 ctor 抛出 exception 时, 才会调用这些重载版的 operator delete()。 它只可能这样被调用,主要用来归还未能完全创建成功的 object 所占用的 memory。