对于熟悉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;
}
运行结果: