虚函数的定义与使用
虚函数的定义很简单,只要在成员函数原型前加一个关键字virtual即可。如果一个基类的成员函数定义为虚函数,那么,它在所有派生类中也保持为虚函数,即使在派生类中省略了virtual关键字。还是使用例1的例子,我们把基类的成员函数定义为虚函数,并将main函数也进行修改,即:
使用虚函数时的函数调用。
该程序的运行结果为:
Vehiclemessage
Carmessage
Vehiclemessage
Boatmessage
下面我们对这个程序做一个简单的分析。基类vehicle的成员函数message()被定义为虚函数,虽然其派生类中的message()成员函数在定义时没有virtual关键字,但根据C++的规定,也都是虚函数。从上面的结果我们可以看到:如果派生类中有与基类对应的方法,并且基类指针指向派生类的对象,那么基类指针调用的方法是派生类的方法。
我们应该注意到:main函数中有四个相同的语句“unicycle→message();”,但是它们的结果并不相同。哪一个类的message()成员函数被调用,不是在编译时确定的,而是根据运行时unicycle指针指向的对象的类型确定的。由于类truck没有覆盖基类的message()成员函数,系统调用的是基类的message()成员函数。
需要注意的是:要达到动态联编的效果,基类和派生类的对应函数不仅名字相同,而且返回类型、参数个数和类型也必须相同。
下面的情况说明并不是所有覆盖的函数都会变成虚函数。
根据例1改写。
};
还有一个有意思的情况,如例3所示。
根据例1改写。
我们把派生类的虚函数定义为私有,再进行上面的调用,就会出现注释中的情况。
因为message()是car类的私有成员,所以在类外应该访问不到它,正像“mycar.message();”会出现编译错误一样。但是,如果我们把它定义成虚函数,就可以通过基类指针访问到了。
对于“v→message();”,虽然v是vehicle类型指针,但是,它调用的是虚函数,所以实际上调用的是car类的message()函数。
3)多态的实现
在这一部分,我们简要地介绍一下在C++中动态联编多态是怎样实现的。
实现动态联编机制的几个条件是:
(1)以公有继承为基础。
(2)虚函数为重要条件。
(3)在一般函数中实现动态联编要使用对象的引用或指针。
关于动态联编。
程序运行结果为:
.
.
.
分析:
该程序中定义了point类和circle类,并且circle类共有继承point类。另外,成员函数area()是虚函数,这是满足动态联编的两个重要条件。在主函数中,定义一个circle类对象c,又定义了point类的对象p1,对象引用p2和指向对象指针p3,并将对象c1的值或地址值分别赋初值给了p1、p2、p3。由于circle类是point类的子类型,因此这些操作是合法的。
由于具备动态联编的两个基本条件,p2.area()和p3→area()都将选用circle类中的area()函数。而p1.area()和p2.point::area()中选用的是point类的area()函数,所以显示上述结果。
在构造函数和析构函数中使用虚函数。
inA+
5,8
inZ+
inZ-
inA-
分析:
该程序中定义了3个类:X类、Y类和Z类。在X类中定义了两个虚函数fun1()和fun2()。在Y类中,构造函数Y(inti)中调用了虚函数fun1(),在析构函数~Y()中调用了虚函数fun2()。在Y类中又定义一个成员函数fun(),该函数调用了虚函数fun1()。在Z类中,定义了虚函数fun1()。
主函数中创建Z类对象a时,应调用Z类的构造函数,则先调用基类Y类的构造函数,而Y类构造函数又先调其基类X类的构造函数,即先给X类数据成员x初始化为5,再调用X类的fun1()函数,输出显示“inA+”,然后给Z类的数据成员z初始化为8。创建对象a结束。
主函数最后执行a.fun();语句,先调用从Y类继承的fun()函数,该函数中调用fun1(),该成员函数调用虚函数,这里采用动态联编,则选用Z类中的fun1()函数,输出显示“inZ+”。
结束主函数前要将对象a释放,则调用Z类的析构函数,该函数调用fun2(),输出显示“inZ-”。接着调用Y类的析构函数,该函数又调用从X类中继承的fun2()函数,输出显示“inA-”。
从该程序的执行中可以看出以下两点:
(1)构造函数和析构函数中出现的虚函数,采用静态联编。即用该类的或从基类继承的同名函数。
(2)成员函数中调用虚函数,采用动态联编。
超实用性的Python零基础入门到进阶视频源码淘宝¥2购买已下架好了,本文到此结束。如果对编程、计算机、程序员方面感兴趣的话,欢迎私信联系我,随时交流!点个