虚函数[1]
问题:还记得第7章的例子吗[2]?
例7-3 类型转换规则举例
#include <iostream>using namespace std;class Base1 {//基类Base1定义public:void display() const {cout << "Base1::display()" << endl;}};class Base2 : public Base1 {//公有派生类Base2定义public:void display() const {cout << "Base2::display()" << endl;}};class Derived : public Base2 {//公有派生类Derived定义public:void display() const {cout << "Derived::display()" << endl;}};void fun(Base1 *ptr) {//参数为指向基类对象的指针ptr->display();//"对象指针->成员名"}int main() {//主函数Base1 base1; //声明Base1类对象Base2 base2; //声明Base2类对象Derived derived; //声明Derived类对象fun(&base1); //用Base1对象的指针调用fun函数fun(&base2); //用Base2对象的指针调用fun函数fun(&derived); //用Derived对象的指针调用fun函数return 0;}
程序运行结果:
对程序的一些说明:
程序的本意时希望能够写一个通用的显示函数fun(),根据需要指向不同的派生对象,然后调用各自display函数。但是没有达到这个期望的效果。为什么程序没有达到期望效果?运行结果都是调用Base1的display函数。所以建议不要重新定义继承而来的非虚函数。
在编译阶段,编译器根据指针无法去判断在运行时它会指向一个什么类型的对象。
用虚函数能解决上述问题的原理:
在编译阶段没法正确地决定,就推迟这个决定,留到运行时在确定。程序运行时就能够知道指针在某个时刻指向的实际对象。
怎么实现上述原理:
添加一个virtual关键字即可。它的意思是指示编译器不要在编译阶段做静态绑定,要为运行阶段做动态绑定做好准备。
注意:加了virtual的虚函数都要在类外去实现函数体,不能写成内联函数(因为内联函数是静态绑定的)。
例8-4通过虚函数实现运行时多态
现在我们来改进一下第7章的程序:同原型的函数在类外写成虚函数。
#include <iostream>using namespace std;class Base1 {public:virtual void display() const; //虚函数};void Base1::display() const {cout << "Base1::display()" << endl;}class Base2 : public Base1 {public:virtual void display() const;};void Base2::display() const {cout << "Base2::display()" << endl;}class Derived : public Base2 {public:virtual void display() const;};void Derived::display() const {cout << "Derived::display()" << endl;}void fun(Base1 *ptr) {ptr->display();}int main() {Base1 base1;Base2 base2;Derived derived;fun(&base1);fun(&base2);fun(&derived);return 0;}
程序运行结果:
参考
^/courses/course-v1:TsinghuaX+00740043_2x__T2+sp/courseware/93f0d3a029d84059a84d02745a1e2bfd/62b1f428ccb14e7bafa80cc5be4519b6/^/p/103992675基类指针调用派生类函数_C++ 多态性:虚函数--基类与派生类类型转换(第7章 05)例子问题解析(学习笔记:第8章 05)...