对于熟悉C++程序设计的程序员来说,virtual关键字还是经常使用的关键字之一。那么在本篇博客中,博主根据自己的学习的经验对virtual进行一些讨论,如果有什么错误或者需要补充的地方,请大家留言评论。
virtual关键字总结来说总共是有三个方面的用途:
1.消除类在多继承情况的下的二义性;
2.声明虚函数,用来实现函数的动态重载;
3.实现一个纯虚函数。
我们将从这三个方面来展开相应的陈述。
一、消除类在多继承情况的下的二义性
假设存在四个类,有这样的派生关系:
我们这几个类定义如下所示:
class A{ public: int a; void display(){ cout<<"A::a="<<a<<endl; } }; class B:public A{ public: int b; }; class C:public A{ public: int c; }; class D:public B,public C{ public: int d; void show(){ cout<<"d="<<d<<endl; } }
根据上述的代码,在最底层的派生类D中包含如下的成员:
可以看到在D类的成员中,存在从基类A中继承到的重复成员。这样的话,会造成类成员的冗余问题,在D类的对象使用A类成员时调用非常的不方便,并且可能会产生混淆。其次,成员的冗余会带来内存资源的浪费。最后,对于基类A的成员,在D类中产生了二义性的问题。
为了解决上述问题,virtual关键字就派上了用场。我们将上述中的代码修改为如下:
class A{ public: int a; void display(){ cout<<"A::a="<<a<<endl; } }; class B:virtual public A{ //声明类B是类A的公用派生类,A是B的虚基类 public: int b; }; class C:virtual public A{ //声明类C是类A的公用派生类,A是C的虚基类 public: int c; }; class D:public B,public C{ //声明类D是类B、C的公用派生类 public: int d; void show(){ cout<<"d="<<d<<endl; } }
根据我们修改后的代码,在最底层的派生类D中包含如下的成员:
这样,就解决了上述中多重继承中产生的二义性的问题。
二、声明虚函数,用来实现函数的动态重载
C++中函数的重载分为静态重载和动态重载。静态重载是通过函数重载来实现的。而函数的动态就需要使用到virtual关键字了。静态重载要求程序编译时就知道调用函数的券部信息,因此,在程序编译时系统就能决定要调用的是哪个函数。动态重载是指程序在运行过程中才动态地确定操作指针指向的对象。我们下述通过一段代码来说明:
class A{ public: int a1; int a2; int a3; //A(); A(int a1=0,int a2=0,int a3=0):a1(a1),a2(a2),a3(a3){} void display(){ cout<<"A::a1="<<a1<<endl; cout<<"A::a2="<<a2<<endl; cout<<"A::a3="<<a3<<endl; } }; class B:public A{ public: int b1; int b2; int b3; B(int b1=0,int b2=0,int b3=0):b1(b1),b2(b2),b3(b3){} void display(){ cout<<"B::b1="<<b1<<endl; cout<<"B::b2="<<b2<<endl; cout<<"B::b3="<<b3<<endl; } }; int main() { A a(1,2,3); B b(11,22,33); A *point=&a; point->display(); point=&b; point->display(); return 0; }
运行结果:
指针指向对象a时,用指针调用display()函数,打印a1、a2、a3的值我们可以正常理解。但是当指针指向对象b时,用指针调用display()函数,却依然调用的是对象a的成员函数display()。但此时,我们想通过这种方式来实现对对象b中display()函数的调用该如何解决呢?这就要用到virtual关键字来定义虚函数了。我们将上述代码进行如下修改:
class A{ public: int a1; int a2; int a3; //A(); A(int a1=0,int a2=0,int a3=0):a1(a1),a2(a2),a3(a3){} virtual void display(){ //将基类A中的display()函数定义为虚函数 cout<<"A::a1="<<a1<<endl; cout<<"A::a2="<<a2<<endl; cout<<"A::a3="<<a3<<endl; } }; class B:public A{ public: int b1; int b2; int b3; B(int b1=0,int b2=0,int b3=0):b1(b1),b2(b2),b3(b3){} void display(){ cout<<"B::b1="<<b1<<endl; cout<<"B::b2="<<b2<<endl; cout<<"B::b3="<<b3<<endl; } }; int main() { A a(1,2,3); B b(11,22,33); A *point=&a; point->display(); point=&b; point->display(); return 0; }
运行结果:
此时就达到了我们想要的结果。
三、实现一个纯虚函数。
如果一个类中包含纯虚函数,那么这个类就是抽象类。抽象类不可以实例化对象。
纯虚函数的一般形式为:
virtual 函数类型 函数名 (参数列表)=0;
下述我们举一个抽象类的例子:
class A{ public: int a1; int a2; int a3; A(int a1=0,int a2=0,int a3=0):a1(a1),a2(a2),a3(a3){} virtual void display() const=0; }; class B:public A{ public: B(int b1=0,int b2=0,int b3=0):A(b1,b2,b3){} virtual void display() const{ cout<<"A::a1="<<A::a1<<endl; cout<<"A::a2="<<A::a2<<endl; cout<<"A::a3="<<A::a3<<endl; } }; int main() { B b(11,22,33); b.display(); return 0; }
运行结果: