典型的示例是抽象形状类,然后可以将其导出为正方形,圆形和其他具体形状。
父类:
让我们从多态类开始:
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 << "t他是一个正方形的开始 " << top_left.x << ", " << top_left.y << " 长度为 " << side_length << std::endl; } };
一些解释:
您可以定义或覆盖父类的任何虚函数。函数在父类中是虚拟的事实使其在派生类中是虚拟的。无需virtual再次告诉编译器关键字。但是建议您override在函数声明的末尾添加关键字,以防止由于函数签名中未引起注意的变化而引起的细微错误。
如果定义了父类的所有纯虚函数,则可以实例化该类的对象,否则它也将成为抽象类。
您没有义务覆盖所有虚拟功能。如果需要,您可以保留父版本。
实例化的例子
int main() { Square square(Point(10.0, 0.0), 6); // 我们知道这是一个正方形,编译器也 square.describe_object(); std::cout << "Surface: " << square.get_surface() << std::endl; Circle circle(Point(0.0, 0.0), 5); Shape *ps = nullptr; // 我们还不知道对象的真实类型 ps = &circle; // 这是一个圆,但也可以是一个正方形 ps->describe_object(); std::cout << "Surface: " << ps->get_surface() << std::endl; }