Pare5 虚函数
虚函数是实现动态绑定的函数,什么是动态绑定,为什么需要动态绑定嘞?
回忆第七场那个例题:没有实现期望中的通用的显示函数。
不成功的原因就是在编译阶段,编译器根据指针无法去判断在运行时,他会指向一个什么类型的对象,所以他只能说指针是什么类型的他就调用那个类定义的display函数。这种情况下我们特别希望告诉编译器,对了在编译阶段,你没法正确决定。那怎么办了?你推迟这个决定在编译的时候先别确定,这个display函数调用表达式跟那个函数体对应。先别对应,把他留着,留到运行的时候在确定,那么运行时当然就能够知道,指针在某个时刻指向的实际对象是什么,怎么告诉编译器这个事了?就用一个virtual关键字。
用了一个virtual关键字,一切问题都得到解决。
初识虚函数
用virtual关键字说明的函数
虚函数是实现运行时多态性基础
C++中的虚函数是动态绑定的函数
虚函数必须是非静态成员函数,虚函数经过派生之后,就可以实现运行过程中的多态。(虚函数是属于对象的,不是属于整个类的,他在运行的时候,只需要用指针去定位该调用那个函数体)
什么函数可以是虚函数
一般成员函数可以是虚函数;
构造函数不能是虚函数
析构函数可以是虚函数
一般虚函数成员
虚函数的声明
Virtual 函数类型 函数名 (形参表)
虚函数声明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候
在派生类中可以对基类中的成员函数进行覆盖。
虚函数一般不能声明为内联函数,因为对虚函数的调用需要动态绑定,而对内联函数的处理是静态的。
小结:virtual
派生类可以不显式地用virtual声明虚函数,这时系统就会用以下规则来判断派生类的一个函数成员是不是虚函数:
该函数是否与基类的虚函数有相同的名称,参数个数以及对应参数类型。
该函数是否与基类函的虚函数有相同的返回值或者满足类型兼容规则的指针、引用型的返回值;
如果从名称、参数及返回值三个方面检查之后,派生类的函数满足上述条件,就会自动确定为虚函数。这时,派生类的虚函数便覆盖了基类的虚函数。
派生类中的虚函数还会隐藏基类中同名函数的所有其他重载形式。
一般习惯于在派生类的函数中也使用virtual关键字,以增加程序的可读性。
例题代码
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void display() const;//virtual是对第七章的问题上进行一点点修改。就是高数编译器凡是遇到对display这个函数调用,都不要在编译的时候马上做决定。
}; //告诉编译器不要在编译阶段做静态绑定,要在运行阶段做动态绑定。
//加了virtual的函数都在在类外去实现函数,不能在类里面实现类联的了
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;
}