C++純虛擬函式和抽象類詳解

2020-07-16 10:04:22
純虛擬函式就是沒有函數體的虛擬函式。包含純虛擬函式的類就叫抽象類。下面的類 A 就是一個抽象類:
class A {
private:
    int a;
public:
    virtual void Print() = 0;  //純虛擬函式
    void fun1() { cout << "fun1"; }
};
Print 就是純虛擬函式。純虛擬函式的寫法就是在函數宣告後面加=0,不寫函數體。純虛擬函式實際上是不存在的,引入純虛擬函式是為了便於實現多型。

之所以把包含純虛擬函式的類稱為“抽象類”,是因為這樣的類不能生成獨立的物件。例如定義上面的 class A 後,下面的語句編譯都會出錯:
A a;
A* p = new A;
A a[2];
既然抽象類不能用來生成獨立物件,那麼抽象類有什麼用呢?抽象類可以作為基礎類別,用來派生新類。可以定義抽象類的指標或參照,並讓它們指向或參照抽象類的派生類的物件,這就為多型的實現創造了條件。獨立的抽象類的物件不存在,但是被包含在派生類物件中的抽象類的物件是可以存在的。

抽象類的概念很符合邏輯。在《C++多型的好處和作用》一節中,我們設計了一款“魔法門”遊戲,其中 CCreature 類的寫法如下:
class CCreature {  //“怪物”類
protected:
    int lifeValue, power;
public:
    virtual void Attack(CCreature* p) {}
    virtual void Hurted(int nPower) {}
    virtual void FightBack(CCreature* p) {}
};
在該程式中,實際上不需要獨立的 CCreature 物件,因為一個怪物物件要麼代表“狼”,要麼代表“龍”,要麼代表“雷鳥”,總之是代表一種具體的怪物,而不會只是一個抽象的、什麼都不是的“怪物”類的物件。所以,上面的 CCreature 類中的 Attack、Hurted、FightBack 成員函數也都沒有實際操作。

既然如此,將上面三個成員函數宣告為純虛擬函式,從而把 CCreature 類變成一個抽象類,就是很恰當的了。因此,CCreature 類的改進寫法如下:
class CCreature {  //“怪物”類
protected:
    int lifeValue, power;
public:
    virtual void Attack(CCreature* p) = 0;
    virtual void Hurted(int nPower) = 0;
    virtual void FightBack(CCreature* p) = 0;
};
同理,對於《C++多型的好處和作用》一節中的幾何形體程式,幾何形體物件要麼是圓形,要麼是三角形,要麼是矩形,等等,也不存在抽象的 CShape 類的物件,因此 CShape 類應該如下改寫為抽象類:
class CShape  //基礎類別:形體類
{
public:
    virtual double Area() = 0;  //求面積
    virtual void Printlnfo() = 0;  //顯示資訊
};
如果一個類從抽象類派生而來,那麼當且僅當它對基礎類別中的所有純虛擬函式都進行覆蓋並都寫出函數體(空的函數體{}也可以),它才能成為非抽象類。

思考題:在抽象類的成員函數內可以呼叫純虛擬函式,但是在建構函式或解構函式內部不能呼叫純虛擬函式。為什麼?