静态多态(编译器/早绑定)
如函数重载
class A { public: void do(int a); void do(int a, int b); };
动态多态(运行期/玩绑定)
虚函数:用virtual修饰成员函数,使其成为虚函数
动态绑定:当使用基类的引用或指针调用一个虚函数时将发生动态绑定
注意:
可以将子类的对象赋值给父类的指针或引用,反之不可
非类成员函数不能是虚函数
静态函数不能是虚函数
构造函数不能是虚函数(因为在调用构造函数是,虚表指针并没有在对象的内存空间中必 须要构造函数电用完后才会形成虚表指针)
内联函数不能表现出多态性时的虚函数;
虚析构函数
虚析构函数是为了解决父类的指针指向子类的对象,并用父类的指针删除子类的对象
用来解决浅拷贝导致的堆区内存重复释放的问题(是吗?我也忘了)
纯虚函数
纯虚函数是一种特殊的虚函数,在父类中不能对虚函数给出有意义的时限,而把他声明为纯虚函数,他的视线留给该父类的子类去实现
虚函数、纯虚函数
1.类里面声明了虚函数,这个函数是可以实现的,哪怕是空实现,它的作用就是为了让这个函数在它的子类里面可以被覆盖,这样的话编译器就可以使用后期晚绑定来达到多态,纯虚函数只是一个接口,是一个函数声明,要留到子类中实现
2.虚函数在子类里面可以不重写,纯虚函数必须在子类实现才可以实例化子类
3.虚函数的类用于实作继承,继承接口的同时也继承了父类的实现,纯虚函数关注的是接口的统一,由子类实现
4.带纯虚函数的类叫抽象类,这种累不能直接实例化对象,而只能北京城,并重写其虚函数后,才能使用。抽象类被继承后,子类可以集成式抽象类也是普通类。
虚函数指针、虚函数表
虚函数指针:在含有虚函数类的对象中,指向虚函数表,在运行时确定
虚函数表:在程序只读数据段,存放虚函数指针,如果派生类实现了基类的某个虚函数,则在虚表中覆盖原本基类的那个虚函数指针,在编译时根据类的声明创建。
虚继承
虚继承用于解决多继承条件下产生的菱形问题(浪费存储空间,存在二义性)
低层实现原理和编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(4字节)和虚基类表(不占内存),当虚基类的子类被当作父类继承时,虚基类指针也会被继承。
实际上 vbptr是指虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table)虚表中记录了虚基类与本类偏移地址,通过偏移地址找到虚基类成员,而虚继承也不像普通多继承那样维持着公共基类的两份同样的拷贝,节省了存储空间