1.关于vptr和vtbl
编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。
类的每个虚成员占据虚函数表中的一行。
如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。
虚 函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。
简称为V-Table。在这个表中,主要是一个类 的虚函数的地址表,
这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。
这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,
所以,当 用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,
它就像一个地图一样,指明了实际所应该调用的函数。
编译器应该是保证虚函数表的指针存在于对象实例中最前面的
位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。
这意味着可以通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
2.关于this指针
动态绑定需要满足三个条件:
1.指针
2.向上转型
3.虚函数
3.关于dynamic binding
B b;
A a = (A) b;
a.vfunc1();
该情况是静态绑定,因为是用对象来调用,不是用指针来调用
A* pa = new B;
pa->vfunc1();
符合动态绑定的三个要点,pa为指针,pa有向上转型,vfunc1为虚函数
4 const
double real() const { return re;}
当成员函数的const和non-const版本同时存在,const object只能调用const版本,non-const object只能调用non-const版本
const成员函数有两个作用:
1.声明该成员函数不修改成员数据
2.保证const对象能够调用该成员函数
非const对象可调用const成员函数,反过来则不行,因为非const成员函数有修改成员数据的可能性,而const对象不能修改,所以反过来编译会出错
5 new 和 delete
new 和 delete 是表达式,内部的流程步骤都是一样的,无法进行重载,可进行重载的是operator new 和
operator delete
全局operator new 和 operator delete的重载不可以被声明在一个namespace内
//这里的函数是编译器去调用, 所以size是编译器给出.
void* operator new[]( size_t size ) { return malloc(size);}
void* operator delete(void* ptr ) { free(ptr);}
void* operator delete[](void* ptr ) { free(ptr);}
重载 member new , delete
在class里面重载new, delete
class foo{ public: void* operator new(size_t size); void operator delete(void *, size_t size); //size为可选 …….
};
```那么你在: foo *a = new foo; delete a; 就会调用上面重载的函数.
new[] , delete[] 也如此.
#6.实例
当类中重载了new , delete , 而又想调用全局的new , delete 可以这样写: ::delete a;
string类内其实是一个指针.
当创建一个数组的时候, 内存当中就会多分配一个指针,该指针用于保存当前数组个数.
#7.重载new(),delete()示例
允许重载成员函数new(….) 其中参数中,必须有第一个且第一个必须是size_t size. 其余参数以new所指定的placement argument为初值.
Foo* p = new(300,’c’)Foo; //这里是三个参数
我们也可以重载类成员函数 operator delete() ,写出多个版本. 但他们绝不会被 通常所使用的delete调用.只有当new所调用的ctor抛出 异常,才会调用这些重载版的operator delete(). 它们只能这样被调用,主要用来归还未能完全创建成功的对象所占用的内存.
#8.Basic_String使用new(extra)扩充申请量
Basic_String在重载new()过后,传递了一个extra参数, 用于后台自动多申请extra空间。