1.vptr(虚指针)和vtbl(虚表)
a.只要类中有虚函数(不论多少个),这个类的实际大小会比类中所有的数据大小相加还要多4,这是因为类中存在虚指针(vptr),同时,虚指针将会指向一个虚表(vtbl),虚表可以被理解成一个数组,其作用是虚函数表的作用是保存类中的虚函数的地址。
b.如上图所示虚函数的调用过程:
取出vptr即得到虚函数表的地址->在虚表中找到对应虚函数地址->通过得到的地址调用函数。
事例:上图中,对象a与b均有虚函数vfunc2(),但是a与b中的vptr不同,它们对应的vtbl就不同(对象a对应A:: vfunc2(),对象b对应B:: vfunc2()),相应的,它们的vtbl中所对应的虚函数地址也不同。
c.动态绑定:
当满足以下三个条件时,编译器会进行动态绑定:
1).通过指针调用函数;
2).指针要做向上转型动作;
3).指针调用的是虚函数。
2.关于this
a.通过对象调用函数时,那个对象的地址就是this
b.this是一根指针,this所指向的对象叫做this对象;
c.C++中,所有的成员函数都有一个隐藏的this pointer参数。
tips:
this在成员函数的开始前构造,在成员函数的结束后清除。
由于this并不是一个常规变量,所以不能取得this的地址。
3.关于const
修饰常量,用const修饰的变量是不可变的。
当const的位置在函数的参数列表(即小括号)后面,且在函数体(即花括号)前面时(用来修饰成员函数),表示这个函数不改变class中的数据。一般的全局函数是不能用const来修饰函数体的
图中红框列成表为:
当成员函数的const与非const版本同时存在时:
4.关于New和Delete
New的动作:
a)分配内存——编译器调用operator new(n)函数(C++),实际调用的是malloc(n)函数(c语言);
b)转型;
c)调用构造函数(ctor)
delete的动作:
a)先调用析构函数(dtor);
b)释放内存——调用delete(n)函数(C++),其实调用的是free(n)(C语言)
5.Operator new和Operator delete
a.对全局函数::operator new和::operator delete进行重载(::表示这是全局的),在使用时,编译器先检查是否有对::operator new和::operator delete进行重载,如果有,则调用重载的,否则调用默认的。对::operator new和::operator delete进行重载是一件危险的事情,因为这样会导致所有的new与delete都将使用你所定义的,这会导致分配空间不确定。
b.也可以在class中进行member operator new/delete,这样做只针对这个类使用自定义的内存管理:
c.强制使用全局的new与delete:
Tips:使用new和delete,编译器会首先寻找类内是否有重新定义的operator new和operator delete函数,之后再查找全局作用域是否有重新定义的operator new和operator delete函数,接着再调用标准库的operator new和operator delete函数。
c.当类内自定义operator new和operator delete函数时,默认为static函数,因为operator new发生在对象构造前,而operator delete发生在对象销毁后,不属于对象的生命周期内。
d.类型size_t是标准库定义的一种类型,不必传入实参,编译器会为我们计算需要的内存大小,并自行传入size_t形参。