定義多型類
典型的例子是抽象形狀類,然後可以將其匯出為正方形,圓形和其他具體形狀。
父類:
讓我們從多型類開始:
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;
}