虚函数
看这样一个例子:
先定义一个类(人类),类里有一个成员函数:人有俩眼睛
class Human { private: /* data */ public: Human(/* args */); ~Human(); void eyes(); }; Human::Human(/* args */) { } Human::~Human() { } void Human::eyes() { cout<<"human have two eyes"<<endl; }
再用这个类派生一个子类:杨戬,那很显然,杨戬有三只眼睛
class YangJian:public Human { private: /* data */ public: YangJian(/* args */); ~YangJian(); void eyes(); }; YangJian::YangJian(/* args */) { } YangJian::~YangJian() { } void YangJian::eyes() { cout<<"YangJian have three eyes"<<endl; }
在主函数中分别调用这两个类的函数
int main(int argc, char const *argv[]) { Human xiaoming; xiaoming.eyes(); YangJian yangjian; yangjian.eyes(); }
输出结果很美好
human have two eyes
YangJian have three eyes
人有俩眼睛,杨戬有仨。
没有任何问题。
现在我要在一个函数中调用这个eyes
void eyescount(Human &p) { p.eyes(); }
接下来在主函数中分别对两个对象调用这个函数
int main(int argc, char const *argv[]) { Human xiaoming; xiaoming.eyes(); YangJian yangjian; yangjian.eyes(); eyescount(xiaoming); eyescount(yangjian); }
讲道理,输出结果应该和前面一样。小明俩眼睛,杨戬仨眼睛
但是实际上的输出:
human have two eyes
YangJian have three eyes
human have two eyes
human have two eyes
问题出现了!
我传入的是YangJian这个对象的参数,但是进入函数之后调用的却是他的父类Human的函数。
也就是说,只有我这个函数写成这个样子,它才肯调用YangJian 的 eyes()
void eyescount(YangJian &p) { p.eyes(); }
那我Human有各种子类,除了杨戬,
我还有独眼的夏侯惇,还有仨眼睛的马王爷,还有三头六臂六个眼睛的哪吒,再带上几个千手千眼的菩萨。那我这个函数得重载多少次
那么为了解决这样的问题,就有了虚函数这样一个概念。
现在回到最开始定义Human的成员函数里面
class Human { private: /* data */ public: Human(/* args */); ~Human(); virtual void eyes(); };
我们在父类函数声明之前,加一个virtual关键字,也就是本文的虚函数
其他地方没有任何改动,再运行一遍这个程序。
human have two eyes
YangJian have three eyes
human have two eyes
YangJian have three eyes
这样打印出来的结果就回归正常了
有了虚函数,基类指针指向基类对象时就使用基类的成员(包括成员函数和成员变量),指向派生类对象时就使用派生类的成员。换句话说,基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现方式,我们将这种现象称为多态(Polymorphism)。