1.1 基类成员在派生类中的访问属性
1.2继承时导致的二义性
1.3 多基继承
2.虚函数的多态
2.1虚函数的定义
2.2派生类中可以根据需要对虚函数进行重定义
2.3 虚函数的访问
2.4哪些函数不能定义为虚函数
2.5虚函数表指针(vptr)和虚基类表指针(bptr)
2.5.1 虚函数表指针vptr
2.5.2含静态变量、虚函数的类的空间计算
2.5.3虚基类表指针
2.5.4 虚拟继承时构造函数的书写
2.5.5虚函数
3.运行时类型识别与显示转换
3.1 typeid
3.2 显式转换
1.继承
如果一个类有多个直接基类,而这些直接基类又有一个共同的基类,则在最底层的派生类中会保留这个间接的共同基类数据成员的多份同名成员。提出虚继承,虚继承时,公共基类在对象模型中只有一份拷贝。
1.1 基类成员在派生类中的访问属性
这里一定要区分清楚派生类对象和派生类中的成员函数对基类的访问时不同的。
1.2继承时导致的二义性
1)在公有继承下(私有,保护继承时,不能隐式转换)下,派生类的对象/对象指针/对象引用可以赋值给基类的对象/对象指针/对象引用(发生隐式转换)。但基类的对象/对象指针/对象引用不能赋值给派生类的对象/对象指针/对象引用。因为派生类包含了基类的所有信息,而基类缺乏派生类中的信息。
2)c++容许把基类的对象指针/对象引用强制转换为(显式)派生类的对象指针/对象引用。
3)一个指向基类的指针可以用来指向该基类公有派生类的任何对象,这是c++实现程序运行时多态性的关键。
1.3 多基继承
当继承基类时,在派生类中就获得了基类所有数据成员的副本,该副本称为子对象。
类mi会包含的的d1的子对象和d2的子对象。如果多个基类中存在同名成员的情况,造成编译器无从判断具体要访问那个基类的成员,则称对基类成员访问的二义性问题。(解决办法:可以加限定符基类)2.虚函数的多态
多态是面向对象的精髓。可以概括为一个接口,多种方法。通俗来讲,多态是指同一个操作作用于不同的对象就会产生不同的响应。多态性分为静态多态和动态多态。其中的函数重载和运算符重载属于静态多态。虚函数属于动态多态性。c++是通过虚函数实现动态多态的。
2.1虚函数的定义
虚函数的定义是在函数原型前加一个关键字virtual即可。
如果一个基类成员定义为虚函数,那么,他在所有派生类中也保持为虚函数,即使在派生类中省略了virtual关键字,也任然是虚函数。
2.2派生类中可以根据需要对虚函数进行重定义,重定义的格式要求:
1)与基类的虚函数有相同的参数个数;
2)与基类的虚函数有相同的参数类型;
3)与基类的虚函数有相同的返回类型。或者与基类的虚函数相同,或者返回指针(引用),并且派生类虚函数所返回的指针(引用)类型是基类中被替换的虚函数所返回的指针(引用)类型的子类型(派生类型)。
2.3 虚函数的访问
虚函数可以通过对象名访问,此时编译器采用的是静态编译。
1)通过对象名访问虚函数时,调用哪个类的函数取决于定义对象名的类型。对象类型是基类时,就调用基类的函数。对象类型是子类时就调用子类的函数。
2)使用指针访问非虚函数时,编译器根据指针本身的类型决定要访问那个函数,而不是根据指针指向的对象类型。
3)使用指针访问虚函数时,编译器根据指针所指对象的类型决定要访问那个函数,而不是根据指针本身的类型。
4)使用引用访问虚函数,与使用指针访问虚函数类型,不同的是,引用一经声明,引用变量本身无论如何改变其调用的函数都不会改变,始终指向开始定义时的函数。在一定程序上提高了代码的安全性。(受限制的指针)
总结:
c++中函数调用默认不使用动态绑定,要触发动态绑定需满足两个条件:
a.只用指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不能进行动态绑定。
b.必须通过基类类型的引用或指针进行函数调用。
2.4哪些函数不能定义为虚函数
普通函数(类的非成员函数),静态成员函数,构造函数,友员函数。而内联成员函数和赋值操作符重载函数即使声明为虚函数也毫无意义。
2.5虚函数表指针(vptr)和虚基类表指针(bptr)
2.5.1 虚函数表指针vptr
1)每个类产生一堆指向virtual functions 的指针,放在表格中,这个表格称为虚函数表。