定義多型類

典型的例子是抽象形狀類,然後可以將其匯出為正方形,圓形和其他具體形狀。

父類:

讓我們從多型類開始:

class Shape {
public:
    virtual ~Shape() = default;
    virtual double get_surface() const = 0;
    virtual void describe_object() const { std::cout << "this is a shape" << std::endl; }  

    double get_doubled_surface() const { return 2 * get_surface(); } 
};

如何閱讀這個定義?

  • 你可以使用關鍵字 virtual 通過引入的成員函式定義多型行為。在這裡,get_surface()describe_object() 顯然將以不同於圓形的方式實現。當在物件上呼叫函式時,將在執行時確定與物件的真實類對應的函式。

  • get_surface() 定義為抽象形狀是沒有意義的。這就是為什麼功能跟隨 = 0。這意味著該功能是純虛擬函式

  • 多型類應始終定義虛擬解構函式。

  • 你可以定義非虛擬成員函式。當為物件呼叫這些函式時,將根據編譯時使用的類來選擇函式。這裡以這種方式定義 get_double_surface()

  • 包含至少一個純虛擬函式的類是抽象類。抽象類無法例項化。你可能只有抽象類型別的指標或引用。

派生類

一旦定義了多型基類,就可以派生它。例如:

class Square : public Shape {
    Point top_left;
    double side_length;
public: 
    Square (const Point& top_left, double side)
       : top_left(top_left), side_length(side_length) {}

    double get_surface() override { return side_length * side_length; }   
    void describe_object() override { 
        std::cout << "this is a square starting at " << top_left.x << ", " << top_left.y
                  << " with a length of " << side_length << std::endl; 
    }  
};

一些解釋:

  • 你可以定義或覆蓋父類的任何虛擬函式。函式在父類中是虛擬的這一事實使其在派生類中是虛擬的。無需再次告訴編譯器關鍵字 virtual。但是建議在函式宣告的末尾新增關鍵字 override,以防止由函式簽名中未被注意的變化引起的細微錯誤。
  • 如果定義了父類的所有純虛擬函式,則可以為該類例項化物件,否則它也將成為抽象類。
  • 你沒有義務覆蓋所有虛擬功能。如果符合你的需要,你可以保留父版本。

例項化的示例

int main() {

    Square square(Point(10.0, 0.0), 6); // we know it's a square, the compiler also
    square.describe_object(); 
    std::cout << "Surface: " << square.get_surface() << std::endl; 

    Circle circle(Point(0.0, 0.0), 5);

    Shape *ps = nullptr;  // we don't know yet the real type of the object
    ps = &circle;         // it's a circle, but it could as well be a square
    ps->describe_object(); 
    std::cout << "Surface: " << ps->get_surface() << std::endl;
}