虚函数[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;
}
程序运行结果:
参考
- ^http://www.xuetangx.com/courses/course-v1:TsinghuaX+00740043_2x_2015_T2+sp/courseware/93f0d3a029d84059a84d02745a1e2bfd/62b1f428ccb14e7bafa80cc5be4519b6/
- ^https://zhuanlan.zhihu.com/p/103992675