C++的虚函数、虚继承、抽象类

文章详细介绍了C++中的虚函数概念,包括定义、覆盖与重载的区别、动态绑定的实现以及用途。接着讨论了虚继承的作用和构造顺序,以及抽象类的定义、作用和纯虚函数的特性。这些内容展示了C++中实现多态性和接口设计的关键机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、虚函数

(1)、定义:

(2)、覆盖和重载的区别:

(3)、动态绑定的实现方法:

(4)、虚函数的典型用途:

(5)、有关虚函数的一些规定:

2、虚继承

(1)、虚继承的作用:

(2)、带虚继承时的构造顺序 :        

3、抽象类

(1)、抽象类的定义:

(2)、抽象类的作用:

(3)、纯虚函数:

(4)、声明纯虚函数一般表达式:

4、总结 


1、虚函数

(1)、定义:

        虚函数允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。(指针指哪打哪)

        在基类中用virtual声明成员函数为虚函数,在派生类中重新定义此函数并可改变其功能。当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数,但如果派生类中没有覆盖基类的虚函数,则调用时调用基类的函数定义。

(2)、覆盖和重载的区别

        重载是同一层次函数名相同;覆盖是成员函数在继承层次中函数原型完全相同

(3)、动态绑定的实现方法

        多态主要体现在虚函数上,只要有虚函数存在,对象类型就在程序运行时动态绑定。

        定义一个指向基类对象的指针,并使它指向同一类族中需要调用该函数的对象(可以是基类对象也可以是子类对象),通过该指针变量调用此虚函数。

(4)、虚函数的典型用途:

        父类指针调用子类的函数。

(5)、有关虚函数的一些规定:

  • 只有类的成员函数才能成为虚函数;
  • 静态成员函数不能成为虚函数,因为静态成员函数不受限于某个对象。
  • 内联函数不能成为虚函数,因为内联函数不能在运行中动态绑定其位置。
    • 构造函数不能成为虚函数,析构函数通常是虚函数。
/*虚函数*/

#include <iostream>
using namespace std;
class CEmployee									//定义CEmployee类
{
public:
	int m_ID;									//定义数据成员
	char m_Name[128];							//定义数据成员
	char m_Depart[128];							//定义数据成员
	CEmployee()									//定义构造函数
	{
		memset(m_Name,0,128);					//初始化数据成员
		memset(m_Depart,0,128);					//初始化数据成员
	}
	virtual void OutputName()					//定义一个虚成员函数
	{
		cout << "员工姓名: "<<m_Name << endl;	//输出信息
	}
};
class COperator:public CEmployee				//从CEmployee类派生一个子类
{
public:
	char m_Password[128] = {0};					//定义数据成员并初始化,否则警告C26495
	void OutputName()							//定义OutputName成员函数,自动成为虚函数
	{
		cout << "操作员姓名: "<<m_Name<< endl;	//输出信息
	}
};
int main(int argc, char* argv[])
{
	CEmployee *pWorker = new COperator();		//定义CEmployee类型指针,调用COperator类构造函数
	strcpy_s(pWorker->m_Name,128,"Mr.Wen");		//设置m_Name数据成员信息
	pWorker->OutputName();						//自动用COperator类的OutputName成员函数的定义去覆盖
	pWorker->CEmployee::OutputName();			//如调用基类虚函数的定义必须加载作用域
	delete pWorker;								//释放对象
	return 0;
}
/*运行结果:
操作员姓名: Mr.Wen
员工姓名: Mr.Wen
*/

2、虚继承

(1)、虚继承的作用:

        解决了多个父类派生子类的时候同一个爷爷类时,在派生子类时使其只存在一个爷爷类。

class 爷爷类
{};
class 父类1:virtual [继承方式]爷爷类
{};
class 父类2:virtual [继承方式]爷爷类
{};
class 子类:[继承方式]父类1,[继承方式]父类2,...
{
    [访问控制修饰符;]
    [成员声明列表]
};

(2)、带虚继承时的构造顺序 :        

对于虚继承,在定义子类对象时,先调用爷爷类构造函数,然后按照派生列表生命的顺序依次调用父类的构造函数,最后调用子类的构造函数。析构时相反。

/*虚继承*/

#include <iostream>
using namespace std;
class CAnimal							//定义一个动物类
{
public:
CAnimal()								//定义构造函数
{
	cout << "动物类被构造"<< endl;		 
}
	void Move()							//定义成员函数
	{
		cout << "动物能够移动"<< endl;		 
	}
};
class CBird : virtual public CAnimal	//从CAnimal类虚继承CBird类
{
public:
	CBird()								//定义构造函数
{
	cout << "鸟类被构造"<< endl;			 
}
	void FlyInSky()						//定义成员函数
	{
		cout << "鸟能够在天空飞翔"<< endl;		 
	}
	void Breath()						//定义成员函数
	{
		cout << "鸟能够呼吸"<< endl;		 
	}
};
class CFish: virtual public CAnimal		//从CAnimal类虚继承CFish
{
public:
	CFish()								//定义构造函数
	{
		cout << "鱼类被构造"<< endl;				
	}
	void SwimInWater()					//定义成员函数
	{
		cout << "鱼能够在水里游"<< endl;			 
	}
	void Breath()						//定义成员函数
	{
		cout << "鱼能够呼吸"<< endl;				
	}
};
class CWaterBird: public CBird, public CFish	//从CBird和CFish类派生子类CWaterBird
{
public:
	CWaterBird()								//定义构造函数
	{
		cout << "水鸟类被构造"<< endl;				 
	}
	void Action()								//定义成员函数
	{
		cout << "水鸟即能飞又能游"<< endl;			 
	}
};
int main(int argc, char* argv[])				//主函数
{
	CWaterBird waterbird;						//定义水鸟对象
	return 0;
}
/*运行结果:
动物类被构造
鸟类被构造
鱼类被构造
水鸟类被构造	*/

3、抽象类

(1)、抽象类的定义

        包含有纯虚函数的类称为抽象类。一个抽象类至少包含一个虚函数。

        抽象类只能作为一个基类派生出的新的子类对待,而不能在程序中被实例化(即不能有自己的对象),但是,可以使用指向抽象类的指针。

(2)、抽象类的作用

        在开发程序的过程中并不是所有代码都是由软件构造师自己写的,有时需要调用库函数,有时分给别人写,一名软件构造师可以通过虚函数建立接口,让程序员填写代码实现接口,而自己主要负责建立抽象类。

(3)、纯虚函数

        是指被标明为没有具体实现的虚成员函数,它不具备函数的功能。

        许多情况下,在基类中不能给出虚函数一个有意义的定义,这时可以在基类中将它说明为纯虚函数,由派生类实现。纯虚函数不能被直接调用,仅起到一个与派生类相一致的接口的作用。

(4)、声明纯虚函数一般表达式:

        virtual 类型 函数名(参数列表)=0;  //没有{}即函数体

        纯虚函数不能被继承。当基类是抽象类时,在派生类中必须给出基类中纯虚函数的定义,或在该类中再声明其为纯虚函数。只有在派生类中给出基类所有纯虚函数的实时,该派生类才不再成为抽象类。

/*抽象类*/

#include <iostream>
using namespace std;
class CFigure								//定义类
{
public:
	virtual double getArea() =0;			//虚函数=抽象成员函数
};
const double PI=3.14;
class CCircle : public CFigure				//定义派生类
{
private:
	double m_dRadius;						//定义派生类数据成员
public:
	CCircle(double dR)						//构造函数
	{
		m_dRadius=dR;
	}
	double getArea()						//成员函数
	{
		cout << "圆的面积是=";
		return m_dRadius*m_dRadius*PI;
	}
};
class CRectangle : public CFigure			//定义派生类
{
protected:
	double m_dHeight,m_dWidth;
public:
	CRectangle(double dHeight,double dWidth)//定义构造函数
	{
		m_dHeight=dHeight;
		m_dWidth=dWidth;
	}
	double getArea()						//定义成员函数
	{
		cout << "矩形的面积是=";
		return m_dHeight*m_dWidth;
	}
};
int main()
{
	/*CFigure figure;*/					//纯虚函数不能实例化没有自己的对象,但可以有自己的指针,否则E0322
	CFigure *fg1;						//定义基类对象实例的指针
	fg1= new CRectangle(4.0,5.0);		//指针指向派生类所占内存空间
	cout << fg1->getArea() << endl;
	delete fg1;							//释放指针
	CFigure *fg2;						//定义基类对象实例的指针
	fg2= new CCircle(4.0);				//指针指向派生类所占内存空间
	cout << fg2->getArea() << endl;
	delete fg2;							//释放指针

}
/*运行结果:同一基类不同的实例指针,通过基类内虚函数指向不同的派生类即使函数名相同也会获得不同的结果
矩形的面积是=20
圆的面积是=50.24	*/

4、总结 

特征1特征2特征3用途
虚函数父类成员函数被声明virtual所有子类同名函数自动成为virtual

动态绑定:通过基类指针或引用来访问基类和派生类中的同名函数。(指针指哪打哪)

父类指针调用子类成员
虚继承把基类声明称virtual多个基类派生子类并且多个基类又派生于共同基类(爷类)创建子类对象时,存在多次构建爷爷类的情况

解决了多个父类派生子类的时候同一个爷爷类时,在派生子类时使其只存在一个爷爷类。

抽象类类域里包含纯虚函数(类域可以是基类也可以子类,通常基类)当基类是抽象类时,在派生类中必须给出基类中纯虚函数的定义,或在该类中再声明其为纯虚函数。

纯虚函数不能被直接调用,没有自己的成员对象,仅起到一个与派生类相一致的接口的作用。

软件工程分工协作

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wenchm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值