C++纯虚函数和抽象类的用法(附带实例)
C++实际软件开发过程中,代码编写通常由多人分工协作完成。其中,软件架构师可以通过纯虚函数建立接口和抽象类,由具体程序员填写代码实现接口。
纯虚函数(pure virtual function)是指被不负责具体实现的虚成员函数,它不具备函数的功能。通常情况下,在基类中定义纯虚函数,在派生类中给出具体实现。纯虚函数不能被直接调用,其作用是提供一个与派生类一致的接口。
什么样的函数需要被声明为纯虚函数呢?比如,通过图形类可派生出三角形类、矩形类、圆形类等,每个派生类中都有一个求面积的成员函数,它们都继承自图形类。这个求面积的成员函数,在三角形类、矩形类、圆形类中很容易实现,但在图形类中能否实现呢?
你会发现,图形类是一个抽象类,没法对其求面积。为解决这个问题,就可以在图形类中定义一个求面积的纯虚函数,不负责实现,但可以继承,具体的实现交给派生类去完成。
包含纯虚函数的类称为抽象类,抽象类不能在程序中被实例化(即不能定义抽象类的对象),但可以定义指向抽象类的指针。当基类是抽象类时,派生类中必须给出基类中纯虚函数的实现,或再次声明其为纯虚函数。当派生类给出基类中纯虚函数的具体实现时,该派生类就不再是抽象类。
C++ 中,可以将虚函数声明为纯虚函数,语法格式如下:
【实例】计算圆形、矩形的面积。本实例要求使用纯虚函数计算圆形面积和矩形面积。具体代码如下:
注意,包含纯虚函数的类无法被实例化,因此“CFigure figure;”是错误的。
【实例】输出操作员和系统管理员姓名。本实例将 CEmployee 类定义为抽象类,将 OutputName() 定义为纯虚函数。在派生类 COperator 和 CSystemManager 中实现 OutputName(),输出操作员和系统管理员姓名。具体代码如下:
注意,如果函数不是抽象类的成员函数,就不能用基类指针调用它。
纯虚函数(pure virtual function)是指被不负责具体实现的虚成员函数,它不具备函数的功能。通常情况下,在基类中定义纯虚函数,在派生类中给出具体实现。纯虚函数不能被直接调用,其作用是提供一个与派生类一致的接口。
什么样的函数需要被声明为纯虚函数呢?比如,通过图形类可派生出三角形类、矩形类、圆形类等,每个派生类中都有一个求面积的成员函数,它们都继承自图形类。这个求面积的成员函数,在三角形类、矩形类、圆形类中很容易实现,但在图形类中能否实现呢?
你会发现,图形类是一个抽象类,没法对其求面积。为解决这个问题,就可以在图形类中定义一个求面积的纯虚函数,不负责实现,但可以继承,具体的实现交给派生类去完成。
包含纯虚函数的类称为抽象类,抽象类不能在程序中被实例化(即不能定义抽象类的对象),但可以定义指向抽象类的指针。当基类是抽象类时,派生类中必须给出基类中纯虚函数的实现,或再次声明其为纯虚函数。当派生类给出基类中纯虚函数的具体实现时,该派生类就不再是抽象类。
C++ 中,可以将虚函数声明为纯虚函数,语法格式如下:
virtual 类型 函数名(参数表列)=0;纯虚函数没有函数体,只有函数声明。在虚函数声明的结尾加上“=0”,表明此函数为纯虚函数。
【实例】计算圆形、矩形的面积。本实例要求使用纯虚函数计算圆形面积和矩形面积。具体代码如下:
#include <iostream> using namespace std; class CFigure // 定义图形类 CFigure,因含纯虚函数,为抽象类 { public: virtual double getArea() = 0; // 声明纯虚函数 getArea(),不提供实现 }; const double PI = 3.14; // 定义 PI 为常量 3.14 class CCircle : public CFigure // 定义圆形类 CCircle,继承自 CFigure { private: double m_dRadius; public: CCircle(double dR) // 构造函数,初始化半径 { m_dRadius = dR; } double getArea() override // 在 CCircle 中实现 getArea() { return m_dRadius * m_dRadius * PI; } }; class CRectangle : public CFigure // 定义矩形类 CRectangle,继承自 CFigure { protected: double m_dHeight, m_dWidth; public: CRectangle(double dHeight, double dWidth) // 构造函数,初始化矩形长、宽 { m_dHeight = dHeight; m_dWidth = dWidth; } double getArea() override // 在 CRectangle 中实现 getArea() { return m_dHeight * m_dWidth; } }; int main() { 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; return 0; }程序运行结果为:
20
50.24
注意,包含纯虚函数的类无法被实例化,因此“CFigure figure;”是错误的。
实现抽象类中的成员函数
抽象类通常用作其他类的基类,从抽象类派生的子类如果不是抽象类,则派生类必须实现基类中的所有纯虚函数。【实例】输出操作员和系统管理员姓名。本实例将 CEmployee 类定义为抽象类,将 OutputName() 定义为纯虚函数。在派生类 COperator 和 CSystemManager 中实现 OutputName(),输出操作员和系统管理员姓名。具体代码如下:
#include <iostream> #include <cstring> using namespace std; class CEmployee // 定义 CEmployee 类,该类为抽象类 { public: int m_ID; char m_Name[128]; char m_Depart[128]; virtual void OutputName() = 0; // 定义纯虚函数 OutputName() }; class COperator : public CEmployee // 定义 COperator 类,继承自 CEmployee { public: char m_Password[128]; void OutputName() override // OutputName() 函数的实现 { cout << "操作员姓名:" << m_Name << endl; } COperator() // 默认构造函数 { strcpy(m_Name, "MR"); } }; class CSystemManager : public CEmployee // 定义 CSystemManager 类,继承自 CEmployee { public: char m_Password[128]; void OutputName() override // OutputName() 函数的实现 { cout << "系统管理员姓名:" << m_Name << endl; } CSystemManager() // 默认构造函数 { strcpy(m_Name, "SK"); } }; int main(int argc, char *argv[]) // 主函数 { CEmployee *pWorker; // 定义 CEmployee 类型指针对象 pWorker = new COperator(); // 调用 COperator 类构造函数为 pWorker 赋值 pWorker->OutputName(); // 调用 COperator 类的 OutputName 成员函数 delete pWorker; // 释放 pWorker 对象 pWorker = NULL; // 将 pWorker 设置为空 pWorker = new CSystemManager(); // 调用 CSystemManager 类构造函数为 pWorker 赋值 pWorker->OutputName(); // 调用 CSystemManager 类的 OutputName 成员函数 delete pWorker; // 释放 pWorker 对象 pWorker = NULL; // 将 pWorker 设置为空 return 0; }程序运行结果为:
操作员姓名:MR
系统管理员姓名:SK
注意,如果函数不是抽象类的成员函数,就不能用基类指针调用它。