C++ 虚函数
虚函数
在了解虚函数之前,我们先来考虑一个问题。我们创建一个基类,在它的派生类中声明一个与基类函数同名的函数,声明之后,我们要实现的是通过基类的指针实现对派生类函数的访问。有些人会说,直接将派生类的地址赋值给基类的指针就OK了呀。这样能实现吗?我们通过代码来实验。
#include "pch.h" #include <iostream> using namespace std; class Base1 { public: void display() { cout << "Base1::display()" << endl; } private:
}; class Base2:public Base1 { public: void display() { cout << "Base2::display()" << endl; } private: }; class Base3:public Base2 { public: void display() { cout << "Base3::display()" << endl; } private: }; void fun(Base1 *a) { a->display(); } int main() { Base2 b; Base3 c; fun(&b); fun(&c); }
通过将Base2 、Base3的地址传给Base1的指针,输出结果为:
结果并不是我们预料的那样,访问到的都是基类的函数。那我们怎么实现这样的需求呢?这时我们来了解虚函数。
虚函数是动态绑定的基础。虚函数经过派生之后,在类中就可以实现运行过程中的多态。
在这个例子中,通过基类类型的指针就可以使不同的派生类的不同对象产生不同的行为,从而实现运行过程的多态。
一般虚函数的语法是:
virtual 函数类型 函数名(形参表) { 函数体 }
需要注意的是虚函数的声只能在类的定义的函数原型中声明,而不能在成员函数实现时声明。
在利用虚函数之后,我们再来进行实验:
#include "pch.h" #include <iostream> using namespace std; class Base1 { public: virtual void display() //在函数声明时使用virtual,实现虚函数的声明 { cout << "Base1::display()" << endl; } private: }; class Base2:public Base1 { public: virtual void display() //派生类的同名函数可以不加virtual,但为了代码规范,我们依然加上virtual { cout << "Base2::display()" << endl; } private: }; class Base3:public Base2 { public: virtual void display() { cout << "Base3::display()" << endl; } private: }; void fun(Base1 *a) { a->display(); } int main() { Base2 b; Base3 c; fun(&b); fun(&c); }
结果为:
结果符合我们的期望。实现了对派生类中同名函数的访问。
通过实验我们可以体会到,通过基类的指针就可以访问到正在指向的对象的成员,能够对同一类族中的对象进行同一的处理,抽象程度更高,程序更加简洁、更高效。
另外,我们还需要了解判断成员函数是否是虚函数的规则
- 该函数是否与虚函数同名
- 该函数是否与虚函数有同名的参数个数和类型
- 该函数是否与虚函数有相同的返回值或者满足赋值兼容规则的指针、引用的返回值。
如果满足上面三条规则,那该函数则会被自动认定为虚函数。这时,派生类的虚函数便覆盖基类的虚函数。