C++中当我们一个类继承于一个另一个类时,我们在派生类中不想使用基类中的函数,想重新写一个同名函数,这是被允许的;因此我们的基类与派生类可以有同名的函数;例如我们现在有一个类中已经有了一个函数名为show无参的函数,我们在派生类中再写一个名为show函数,这叫函数重载也称为覆盖和重写; 测试代码:
#include <iostream> using namespace std; class AA { public: void show(){ cout << "我是show1" << endl; } }; class BB :public AA { public: void show(){ cout << "我是show2" << endl; } }; int main() { BB a; a.show(); //输出show2 //a.show(); //此时会报错:没有匹配的函数,因为已经被重写了基类中的函数 //a.AA::show();//正常输出AA类中的数据 return 0; }运行结果:
因为此时派生类中重写了父类中的同名函数,因此在BB类中看到的show的函数是派生类中的重写后的show函数;其实AA类中的show函数还是存在的,并不是说重写了函数后,它就不存在了因此我们还是可以通过指定类中=名去调用AA类中的函数
测试代码:
#include <iostream> using namespace std; class AA { public: AA(){ cout << "AA()的构造函数"<<endl; } ~AA(){ cout << "AA()的析构函数"<<endl; } void show(){ cout << "我是show1" << endl; } }; class BB :public AA { public: BB(){ cout << "BB()的构造函数"<<endl; } ~BB(){ cout << "BB()的析构函数"<<endl; } void show(){ cout << "我是show2" << endl; } }; int main() { //使用指针时在析构时只会调用基类中地析构函数 //AA * d = new BB(); //d->show(); BB a; AA &b = a; b.show(); //delete d; //使用指针时用于释放内存 return 0; }运行结果: (1)引用 (2)指针:
很明显该程序执行的结果并没有按照AA类型的指针指向的真正的内容去执行对应的代码,而我们是想要编译器能够正确地知道AA &b(或指针)所指向地内容是什么类型的而不是根据当前指针或引用的类型去判断调用什么函数,此时我们实现这种动态多态就需要通过使用关键字virtual来实现;
(1)virtual 修饰的函数称为虚函数,其是通过使用virtual关键字后产生一个虚表(虚函数表),然后每一个对象会创建一个虚表,虚表存放当前对象拥有的虚函数 (2)当虚函数被创建后就会被放入虚表,当派生类重写虚函数后,创建派生类对象时会把虚表内的对应函数地址换成派生类中重写的函数地址
注意: (1)每次执行虚函数都会去重新去替换掉原来虚表的位置 (2)当使用虚函数后原来函数的存放位置会分配一个指针用于指向虚表中函数的地址 (3)一个对象可以拥有多个虚函数,但只能有一个虚表
测试代码:
#include <iostream> using namespace std; class AA { public: AA(){ cout << "AA()的构造函数"<<endl; } ~AA(){ cout << "AA()的析构函数"<<endl; } virtual void show(){ cout << "我是show1" << endl; } }; class BB :public AA { public: BB(){ cout << "BB()的构造函数"<<endl; } ~BB(){ cout << "BB()的析构函数"<<endl; } void show(){ cout << "我是show2" << endl; } }; int main() { BB a; AA &b = a; b.show(); return 0; }运行结果:
关于虚表地址: 此时就会根据对象去正确地选择函数调用了