多态、虚函数、抽象类
1、虚函数
1.1 当父类指针或引用指向子类对象,而子类中又覆盖了父类的函数,希望用父类指针或引用调用到正确版本的成员函数,需要把该成员函数声明为虚函数
1.2 调用虚函数时,到底调用哪个版本,是根据调用该函数的对象本身的类型,而不是指向那个对象的指针或引用的类型,即对象的内存空间为谁(父类or子类)开辟就调用谁的成员方法或成员变量
1.3 虚函数目的:父类指针或引用,不管指向父类还是子类,在调用覆盖函数时,可以反映真实情况;有了虚函数,无需向下转型,就可以正确的用父类的指针或引用调用到子类的函数
1.4 如果函数的参数是传值方式,形参是父类对象,实参是子类对象,则在函数内部,用形参调用的成员函数,依然是父类版本。因为传值只是用子类对象给父类对象赋值,父类对象不是指向子类的引用或指针
1.5 如果一个虚函数被其他成员函数调用,子类的版本也会被正确调用
1.6 如果一个类有子类,则这个父类的析构函数必须是虚函数,即虚析构。如果不是虚析构,则当(用delete)删除一个指向子类对象的父类指针时,将调用父类版本的析构函数,子类只释放了来自于父类的那部分成员变量,而没有释放子类扩展的成员变量,造成内存泄漏。
1.7 如果子类的成员函数是虚函数,则子类覆盖后,不写virtual也是虚函数。
1.8 虚函数被调用的时候,到底调用哪个版本,在编译的时候无法确定,只有在执行时才能确定,称为动态绑定。之前的函数调用,是在编译时就可以确定调用哪个版本的函数
1.9 动态绑定使得程序可以照顾到未来增加的代码,比如创建一个新的子类,并在子类中覆盖了父类的虚函数,用之前的父类指针依然可以正确的调用到新子类中的函数,而无需对旧有代码进行修改。
2、抽象基类、纯虚函数
2.1 纯虚函数,没有函数体,不需要实现,在子类中实现纯虚函数的具体功能
2.2 拥有纯虚函数的类,称为抽象类,抽象类提供了不同种类对象的一个通用接口。
2.3 不能创建抽象类的对象,因为抽象类里面的纯虚函数没有实现。
2.4 抽象类只能作为基类使用,即抽象基类,如果想创建子类对象,必须实现抽象基类中的所有纯虚函数,否则,子类依然是抽象类
2.5 不能单独调用抽象类的构造函数,仅可以用于子类构造函数的初始化列表里,用于初始化子类中继承自父类的成员变量
2.6 抽象类不是必须有析构函数,一旦有,必须是虚析构
2.7 不能以传值的方式,向一个函数传递抽象基类的参数。如果函数形参是抽象类,实参是子类,就相当于用子类对象,创建了一个临时的抽象基类对象,后者是不允许的,所以必须以传引用或指针的方式来传参
3、多态:用父类的指针或引用指向子类的对象,在函数调用时可以调用到正确