C++ 多态与虚函数
多态:多态发生在有继承的场景,基类指针调用函数时,根据对象类型不同执行不同的函数,这个特性叫多态
1. 在C++中,使用父类引用指向子类对象时,如果执行的函数是普通函数,则属于地址早绑定,即使传入的是子类的对象,也会执行父类的方法!
class Animal{ public: void speak(){ cout<<"Animal!"<<endl; } }; class Cat :public Animal{ void speak(){//不会被执行 cout<<"Cat!"<<endl; } }; void doSpeak(Animal &animal){ animal.speak();//地址早绑定 } int main(){ Cat cat; doSpeak(cat);//输出"Animal!" return 0; }
2. 为了实现地址晚绑定,也就是能执行子类的方法,应把父类的方法置为虚函数,在父类方法上使用virtual关键字
class Animal{ public: virtual void speak(){//virtual关键字,变为虚函数 cout<<"Animal!"<<endl; } }; class Cat :public Animal{ virtual void speak(){ cout<<"Cat!"<<endl; } }; void doSpeak(Animal &animal){ animal.speak();//执行时动态绑定 } int main(){ Cat cat; doSpeak(cat);//输出"Cat!" return 0; }
C++多态条件:有继承,子类重写父类虚函数
3. 虚函数表
4. 纯虚函数
通常父类实现的虚函数内容是不需要的,因此可以把虚函数改成纯虚函数;
virtual void speak()=0;//不需要写实现了
当类中有了纯虚函数,它就成了抽象类,它就不能实例化对象了。
子类也必须重写父类的纯虚函数,否则不能实例化对象。
2023-------------
5. 如果没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序将根据实际对象类型选择方法
上述前提是子类重写了virtual方法,如果没重写还是继承父类的方法
6. 继承关系中,通常将基类的析构函数设为虚函数
如果不设为虚函数,当有父类指针指向子类对象时,父类指针delete调用的是父类析构函数,子类派生的那部分无法析构
7. 基类中声明了一个函数是虚函数,其派生类同名函数自动成为虚函数,派生类里可以加virtual也可以不加
8. 虚函数表
虚函数是通过虚函数表实现的,子类继承了几个类,就有几个虚函数表
对于使用了虚函数的类,编译器为每个对象添加了一个隐藏成员,是一个指向虚函数表地址的指针;
虚函数表存储了类对象声明的虚函数地址,如果派生类提供了虚函数的新定义,则存储位置替换为新函数地址;
程序运行时,根据虚函数表中对应第k个虚函数的地址,去实际执行类中第k个虚函数
虚函数表存放在全局数据区,虚函数表大小是编译期间确定的;虚函数表指针存放在对象实例中