#include <iostream>
using namespace std; //線
class Line { public: Line(float len); virtual float area() = 0; virtual float volume() = 0; protected: float m_len; }; Line::Line(float len): m_len(len) { } //矩形
class Rec: public Line { public: Rec(float len, float width); float area(); protected: float m_width; }; Rec::Rec(float len, float width): Line(len), m_width(width) { } float Rec::area() { return m_len * m_width; } //長方體
class Cuboid: public Rec { public: Cuboid(float len, float width, float height); float area(); float volume(); protected: float m_height; }; Cuboid::Cuboid(float len, float width, float height): Rec(len, width), m_height(height) { } float Cuboid::area() { return 2 * ( m_len*m_width + m_len*m_height + m_width*m_height); } float Cuboid::volume() { return m_len * m_width * m_height; } //正方體
class Cube: public Cuboid { public: Cube(float len); float area(); float volume(); }; Cube::Cube(float len): Cuboid(len, len, len) { } float Cube::area() { return 6 * m_len * m_len; } float Cube::volume() { return m_len * m_len * m_len; } int main() { Line *p = new Cuboid(10, 20, 30); cout<<"The area of Cuboid is " <<p->area()<<endl; cout<<"The volume of Cuboid is " <<p->volume()<<endl; p = new Cube(15); cout<<"The area of Cube is "<<p->area()<<endl; cout<<"The volume of Cube is "<<p->volume()<<endl; return 0; }
運行結果:
The area of Cuboid is 2200
The volume of Cuboid is 6000
The area of Cube is 1350
The volume of Cube is 3375
本例中定義了四個類,它們的繼承關系為:Line --> Rec --> Cuboid --> Cube。
Line 是一個抽象類,也是最頂層的基類,在 Line 類中定義了兩個純虛函數 area() 和 volume()。
在 Rec 類中,實現了 area() 函數;所謂實現,就是定義了純虛函數的函數體。但這時 Rec 仍不能被實例化,因為它沒有實現繼承來的 volume() 函數,volume() 仍然是純虛函數,所以 Rec 也仍然是抽象類。
直到 Cuboid 類,才實現了 volume() 函數,才是一個完整的類,才可以被實例化。
可以發現,Line 類表示“線”,沒有面積和體積,但它仍然定義了 area() 和 volume() 兩個純虛函數。這樣的用意很明顯:Line 類不需要被實例化,但是它為派生類提供了“約束條件”,派生類必須要實現這兩個函數,完成計算面積和體積的功能,否則就不能實例化。
在實際開發中,你可以定義一個抽象基類,只完成部分功能,未完成的功能交給派生類去實現(誰派生誰實現)。這部分未完成的功能,往往是基類不需要的,或者在基類中無法實現的。雖然抽象基類沒有完成,但是卻強制要求派生類完成,這就是抽象基類的“霸王條款”。
抽象基類除了約束派生類的功能,還可以實現多態。請注意第 51 行代碼,指針 p 的類型是 Line,但是它卻可以訪問派生類中的 area() 和 volume() 函數,正是由於在 Line 類中將這兩個函數定義為純虛函數;如果不這樣做,51 行后面的代碼都是錯誤的。我想,這或許才是C++提供純虛函數的主要目的。
關於純虛函數的幾點說明
1) 一個純虛函數就可以使類成為抽象基類,但是抽象基類中除了包含純虛函數外,還可以包含其它的成員函數(虛函數或普通函數)和成員變量。
2) 只有類中的虛函數才能被聲明為純虛函數,普通成員函數和頂層函數均不能聲明為純虛函數。如下例所示: