C++ 类中会用到的关键字之-virtual(virtual、override、friend、default、delete、final)

C++ 类中会用到的关键字之-virtual(virtual、override、friend、default、delete、final)
本篇内容主要介绍一些类中常常容易混淆的关键字,public/private这里就不再细说!

1.virtual

  1. Ⅰ:虚基类
    虚基类的使用情景
    如果Bbase、Cbase都公有继承了类Base的成员变量iNum,因此类Bbase Cbase都有一个独立的成员变量iNum ,而类Dbase又公有继承了Bbase Cbase,这样类Dbase就有一个重名的成员 iNum,在主函数中调用dbase.iNum时因为类Dbase有一个重名的成员iNum,编译器不知道调用 从谁继承过来的iNum,所以就产生的二义性的问题。正确的做法应该是加上作用域限定符 dbase.Bbase::iNum 表示调用从Bbase类继承过来的iNum。不过 类Dbase的实例中就有多个同样的iNum的实例,就会造成内存空间浪费,及代码维护性不好。所以C++中就引入了虚基类的概念,来解决类似问题。
//示范
#include<iostream>
class Base
{
public:
	Base(){"std::cout << "Here is Base Constructor!";}
    virtual ~Base(){"std::cout << "Here is Base Destructor!";//如有内存分配,需加virtual关键字释放子类中内存分配,详细后面介绍}
    void iNum;
};

class Bbase:public Base
{
public:
   	Bbase(){"std::cout << "Here is Bbase Constructor!";}
    ~Bbase(){"std::cout << "Here is Bbase Destructor!";}
};

class Cbase:public Base
{
public:
   	Cbase(){"std::cout << "Here is Cbase Constructor!";}
    ~Cbase(){"std::cout << "Here is Cbase Destructor!";}
};

class Dbase:public Bbase,public Cbase
{
public:
     Dbase(){"std::cout << "Here is Dbase Constructor!";}
    ~Dbase(){"std::cout << "Here is Dbase Destructor!";}
};

void main()
{
   Dbase dbase;
   std::cout << dbase.iNum << std::endl; //错误,不明确的访问
   std::cout << dbase.Base::iNum << std::endl; //正确,调用基类iNum
   std::cout << dbase.Bbase::iNum << std::endl; //正确,调用Bbase iNum
   std::cout << dbase.Cbase::iNum << std::endl; //正确,调用Cbase iNum
}
  • 使用虚基类之后:在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iNum这个成员,从类Dbase这个角度上来看,变量iNum是从类Bbase与类Cbase继承过来的,而类Bbase Cbase又是从类Base继承过来的,它们都只是保留了一份父类的iNum变量内存地址,实际调用时,则调用Base.iNum。
//虚基类示范
#include<iostream>
class Base
{
public:
	Base(){std::cout << "Here is Base Constructor!" << std::endl;}
    virtual ~Base(){std::cout << "Here is Base Destructor!"<< std::endl;//如有内存分配,需加virtual关键字释放子类中内存分配,详细后面介绍}
    int iNum;
};

class Bbase:virtual public Base
{
public:
   	Bbase(){std::cout << "Here is Bbase Constructor!"<< std::endl;}
    ~Bbase(){std::cout << "Here is Bbase Destructor!"<< std::endl;}
};

class Cbase:virtual public Base
{
public:
   	Cbase(){std::cout << "Here is Cbase Constructor!"<< std::endl;}
    ~Cbase(){std::cout << "Here is Cbase Destructor!"<< std::endl;}
};

class Dbase:public Bbase,public Cbase
{
public:
     Dbase(){std::cout << "Here is Dbase Constructor!"<< std::endl;}
    ~Dbase(){std::cout << "Here is Dbase Destructor!"<< std::endl;}
};

void main()
{
   Dbase dbase;
   std::cout << dbase.iNum << std::endl; //正确
}
  1. Ⅱ.纯虚函数
    纯虚函数可以让类先声明接口,而不需要定义接口,让派生类在继承时再去具体地给出定义。凡是含有纯虚函数的类叫做抽象类。这种类不能声明对象,只能作为基类为派生类服务。除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。
    纯虚函数使用的情景:
    1)纯虚函数是为你的程序制定一种标准,即只要你继承了我,就必须按照我和标准来,实现我所有的方法,否则你也是虚拟的,为了使程序更加通用化,可重用性提高,让所有实现它或继承自它的子类全部按同一标准来工作。
    2)在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
#include<iostream>

class Base
{
public:
	Base(){std::cout << "Here is Base Constructor!" << std::endl;}
    virtual ~Base(){std::cout << "Here is Base Destructor!" <<std::endl;//如有内存分配,需加virtual关键字释放子类中内存分配,详细后面介绍}
    virtual void initBase() = 0;   //定义initBase接口为纯虚函数
};
  1. Ⅲ.虚函数
    虚函数使用情景:

多态:

问题:
多态现在一般的用法,就是拿一个父类的指针去调用子类中被重写的方法。我们直接在子类中写一个同名的成员函数,从而隐藏父类的函数不就行了?

然后有人这样回答:
将父类比喻为电脑的外设接口,子类比喻为外设,现在我有移动硬盘、U盘以及MP3,它们3个都是可以作为存储但是也各不相同。如果我在写驱动的时候,我用个父类表示外设接口,然后在子类中重写父类那个读取设备的虚函数,那这样电脑的外设接口只需要一个。但如果我不是这样做,而是用每个子类表示一个外设接口,那么我的电脑就必须有3个接口分别来读取移动硬盘、U盘以及MP3。若以后我还有SD卡读卡器,那我岂不是要将电脑拆了,焊个SD卡读卡器的接口上去?
所以,用父类的指针指向子类,是为了面向接口编程。大家都遵循这个接口,弄成一样的,到哪里都可以用,准确说就是“一个接口,多种实现“。

动态联编:是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现,动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果

下面看一个虚函数例子:

#include<iostream>
class Base
{
public:
	Base()
	{
		std::cout << "Here is Base Constructor!" << std::endl;
		iNum = 0;
	}
	//如有内存分配,需加virtual关键字释放子类中内存分配
    virtual ~Base(){std::cout << "Here is Base Destructor!" << std::endl;}
    //virtual void initBase() = 0;   
    virtual void getBaseInfo() {std::cout << "iNum" << iNum << std::endl;}
    int iNum ;
};

class InheritClass:public Base
{
public:
   	InheritClass(){std::cout << "Here is InheritClass Constructor!"<< std::endl;}
   	InheritClass(int num)
   	{
   		std::cout << "Here is InheritClass Constructor!" << std::endl;
		iNum = num;
	}
    ~InheritClass(){std::cout << "Here is InheritClass Destructor!" << std::endl;}
	
	//void initBase() {	std::cout << "Here is InheritClass init!" << std::endl;}
	
	void getBaseInfo()
	{
		std::cout << "Here is InheritClass getBaseInfo!" << std::endl;
		std::cout << "iNum" << iNum << std::endl;
	}	
};



int main()
{
	Base* pBase = NULL;
	Base struBase;
	InheritClass struInheritClass(10);
	
	pBase = &struBase;
	pBase->getBaseInfo();
	pBase = &struInheritClass;
	pBase->getBaseInfo();
}
//运行结果
Here is Base Constructor!
Here is Base Constructor!
Here is InheritClass Constructor!
iNum0
Here is InheritClass getBaseInfo!
iNum10
Here is InheritClass Destructor!
Here is Base Destructor!
Here is Base Destructor!

另外:基类的析构函数最好定义为virtual,否则的用基类指针指向new出来的派生类对象时有可能造成内存泄漏(如果派生类内有内存分配!)
请看一下例子:此例子中析构过程中只析构了基类,派生类析构函数并没有调用! 如果将基类析构函数定义为virtual,则会动态调用派生类析构函数!

#include<iostream>
class Base
{
public:
	Base()
	{
		std::cout << "Here is Base Constructor!" << std::endl;
		iNum = 0;
	}
	//如有内存分配,析构函数需加virtual关键字释放子类中内存分配
    ~Base(){std::cout << "Here is Base Destructor!" << std::endl;}
    virtual void getBaseInfo() {std::cout << "iNum" << iNum << std::endl;}
    int iNum ;
};

class InheritClass:public Base
{
public:
   	InheritClass(){std::cout << "Here is InheritClass Constructor!"<< std::endl;}
   	InheritClass(int num)
   	{
   		std::cout << "Here is InheritClass Constructor!" << std::endl;
		iNum = num;
	}
    ~InheritClass(){std::cout << "Here is InheritClass Destructor!" << std::endl;}
	void getBaseInfo(){std::cout << "iNum" << iNum << std::endl;}	
};



int main()
{
	Base* pBaseNew = new InheritClass(50);
	pBaseNew->getBaseInfo();
	delete pBaseNew;
	pBaseNew = NULL;
}
//运行结果
Here is Base Constructor!
Here is InheritClass Constructor!
Here is InheritClass getBaseInfo!
iNum50
Here is Base Destructor!

此篇文章主要介绍c++ 类中用到的virtual关键字,如有错误请各位看官及时联系,便于及时更正!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值