C++中virtual关键字的讨论

       对于熟悉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;
}

        运行结果:


猜你喜欢

转载自blog.csdn.net/qq_38697681/article/details/80038954