定义多态类
典型的例子是抽象形状类,然后可以将其导出为正方形,圆形和其他具体形状。
父类:
让我们从多态类开始:
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;
}