首页 > 编程笔记 > C++笔记 阅读:1

C++纯虚函数和抽象类的用法(附带实例)

C++实际软件开发过程中,代码编写通常由多人分工协作完成。其中,软件架构师可以通过纯虚函数建立接口和抽象类,由具体程序员填写代码实现接口。

纯虚函数(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

程序中定义了矩形类 CRectangle 和圆形类 CCircle,两个类都派生于图形类 CFigure。将 CFigure 类的面积计算方法设置为纯虚函数,这样圆形有圆形面积的计算方法,矩形有矩形面积的计算方法,每个继承自 CFigure 的对象都有自己的面积计算方式,通过 getArea() 成员函数就可以获取面积。

注意,包含纯虚函数的类无法被实例化,因此“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

可见,同样一条语句“pWorker-> OutputName();”,由于 pWorker 指向的对象不同,其行为也不同。

注意,如果函数不是抽象类的成员函数,就不能用基类指针调用它。

相关文章