1 类与类三种关系下的构造与析构
构造由内而外,析构由外而内。这部分内容算是复习一下:OOP——类和类之间的关系(复合、委托、继承)
2 动态绑定:关于vptr和vtbl
更底层的东西:虚指针vptr、虚表vtbl。
只要类中有虚函数virtual,那么对象中就会多一根指针,即虚指针。故查看长度sizeof会多一根指针的长度,多4。父类若有虚函数,则子类一定有虚函数。
class A //A有两个虚函数,两个普通函数
{
public:
virtual void vfunc1();
virtual void vfunc2();
void func1();
void func2();
private:
int m_data1, m_data2;
};
class B:public A//B继承A,改写一个虚函数,有一个虚函数一个普通函数
{
public:
virtual void vfunc1();
void func2();//虽然与A的func2()同名,但没有任何关系!
private:
int m_data3;
};
class C:public B//C继承B,改写一个虚函数,有一个虚函数一个普通函数
{
public:
virtual void vfunc1();
void func2();//虽然与A、B的func2()同名,但没有任何关系!
private:
int m_data1 m_data4;
};
因此,上面一共有8个函数,即下图右边部分的8个。
通过上图我们看出,子类对象有父类的成分。
其中,每个vptr必然指向一个vtbl,vtbl根据写代码的顺序确定n值,可指向所应当调用的函数,根据颜色可以看出。
静态绑定:当用一根指针调用一个普通函数时,会call这个函数名,找到调用函数,称为静态绑定。
动态绑定:当用一根指针调用一个虚函数时,必须通过指针,还要会向上转型,这是动态绑定的三大条件。(如果是通过对象进行调用的,而不是指针,就不用理会动态绑定,一定是静态绑定)。即这根vptr,进而找到vtbl,如果是最终找到调用函数。可以看到上图最后一行表达方式。
例:当图中的p指向C类的对象c时,当用p调用vfunc1时,则通过vptr动态绑定vtbl找到n=0进而调用。
多态:如下图:虽然指针都是在指向A类型,但实际调用可能指向不同的东西,如指向其派生类B,C等。这种指针可以指向很多种类型,很多种形态的现象,就称之为多态。
例:A时shape类,B是矩形类,C是正方形类。故C继承B继承A。为了能让一个容器容纳各种形状,将指向容器的指针为指向A类。每一个类都有各自的draw()函数。如此即可用指向A类的指针来调用各种类型的draw函数,这就是多态。
3 关于this指针
定义:通过一个对象来调用一个函数,那个对象的地址,就是this。
阅读代码时,一定要理解this是什么,否则会迷失。
上图中,this是myDoc的地址,即便调用的是父类的函数,也要进行的是子类定义的操作(在前面的课程中未解释原因,其原因为:编译器通过this调用,而this指针满足上述三条件:1是一个指针、2有向上转型(是子类对象)、3调用的是虚函数。故进行了动态绑定)。运行过程见上图箭头。