先说不声明为虚函数的成员函数吧
现在假设有一个类A,声明了一个非虚函数some_func,输出“A”
然后有一个类B继承类A,并实现(覆盖)了some_func,输出“B”
现在有个运行例子:
定义一个类B的实例 B b,和一个类A的指针 A * a,并且a指向b,如果调用 a->some_func(),结果是什么?
由于a是指向父类A的指针,所以当a指向实例b时,其实只能访问到类B中部分共享的内容,这部分内容中不包括覆盖的函数成员
所以例程的执行结果会是输出"A"
如果希望实现多态性,该怎么做呢?
首先多态性的含义是什么?以下来自百度百科:
对象根据所接受的消息而做出动作,同样的消息被不同的对象接受时可能导致完全不同的行为,这种现象称为多态性。
所以结合我们所学的,就可以理解为什么多态性分为静态多态性和动态多态性了
静态多态性
静态多态性是指定义在一个类或一个函数中的同名函数,它们根据参数表(类型以及个数)区别语义,并通过静态联编实现,例如,在一个类中定义的不同参数的构造函数。
动态多态性
动态多态性是指定义在一个类层次的不同类中的重载函数,它们一般具有相同的函数,因此要根据指针指向的对象所在类来区别语义,它通过动态联编实现。
在用户不作任何干预的环境下,类的成员函数的行为能根据调用它的对象类型自动作出适应性调整,而且调整是发生在程序运行时,这就是程序的动态多态性。即,发出同样的消息被不同类型的对象接收时,有可能导致完全不同的行为。
按照上面的理解,静态多态性一般就是函数的重载,而动态多态性就是在类继承层次之间,当父类指针在父类实例和子类实例中指向切换时,调用一个同名函数会产生不同的结果(前提是父类函数和子类函数的函数体不同)
明白了这一点,我们就要请出我们的virtual关键字了
我们在函数名some_func 前添加一个virtual 关键字,这时some_func 就称为虚函数了。虚函数没那么“虚”,简单地说,它就是实现了我们上面讲到的动态多态性。
子类B在实现自己版本的some_func。
现在再来考虑之前提到的例程,返回结果就不一样了,它会输出”B“,也就是执行了子类的some_func()
如果我们又把a指向一个规规矩矩的类A实例呢?可以发现,父类A的some_func被执行了
这样就清楚了吧?还不清楚?写一个程序亲自试试看吧
BTW,C++规定,当一个成员函数被声明为虚函数时,其派生类中的同名函数也都会自动成为虚函数,因此在派生类重新声明该虚函数时(也就是我们说的“覆盖”),可以加virtual,也可以不加,但习惯上都会加上,这样可以使程序更清晰。