C++编程实践: 抽象基类
本实例来自《C++ Primer Plus》(第六版) 第十三章
题目要求:
假设你正在开发一个图形程序,该程序会显示圆和椭圆等,需要考虑:
- 椭圆要包含椭圆中心坐标,半长轴,半短轴以及方向角的数据。圆要实现圆心坐标,半径等数据。
- 椭圆要包含移动,旋转一定角度,计算面积和缩放等方法,但是圆不需要旋转。
设计思路:
- 虽然圆也是一种椭圆的特殊形势,但是设计成由圆类继承椭圆类显然是十分笨拙的。比较好的办法是涉及一个基类BaseEllipse,圆和椭圆都继承此基类。这样便可以使用指针数组同时管理Circle对象和Ellipse对象、
知识点:
- C++通过纯虚函数提供基类未实现的方法,纯虚函数的声明为在函数声明的结尾处添加“=0”,例如基类中的Area方法:
virtual double Area() const = 0;//a pure virtual function
- 当类声明中包含纯虚函数的时候,则不能创建该类的对象,包含纯虚函数的类只能作为基类,设计时更多作为接口来使用。
- 派生类必须为基类实现纯虚函数的复写(Override),否则不能通过编译。
- 要注意当使用基类的指针数组创建管理派生类对象的时候,指针只能指向基类声明过的权限为public的函数,不能使用派生类中的新的成员函数。
- 复习一下类产生对象的两种方法
Circle *c = new Circle(1, 0, 1);Circle d(1, 1, 0);
总结与疑问:
- 抽象基类一般被用作接口来使用,抽象基类不能实例化对象,包含至少一个纯虚函数的类叫做抽象基类。
- 如果使用抽象基类的指针数组来管理派生类,那么该数组中的指针不能使用派生类中的新方法(即没有在基类中被以任何形式声明过的方法),如果派生类的所有方法都在抽象基类中声明,又会有些类不会用到接口的全部方法。带来设计上的冗余。
代码实现:
BaseEllipse.h(由于问题比较简单,所有函数均使用内联函数,只为了说明设计的思路)
#pragma once//基类指针指向派生类的时候,不能使用派生类新定义的函数的问题。class BaseEllipse {private:double x;double y;public:BaseEllipse(double x0 = 0,double y0 = 0):x(x0),y(y0){}virtual ~BaseEllipse(){}void Move(int nx, int ny) { x = nx; y = ny; }virtual double Area() const = 0;//a pure virtual functionvirtual void Scale(double sa, double sb){};virtual void Scale(double sr){}virtual void Rotate(double nang){}};class Ellipse :public BaseEllipse {private:double a;double b;double angle;public:Ellipse(double x0 = 0, double y0 = 0, double a0 = 0, double b0 = 0, double angle0 = 0) :BaseEllipse(x0, y0) { a = a0; b = b0; angle = angle0; }virtual double Area() const { return 3.14*a*b; }virtual void Scale(double sa, double sb) { a *= sa; b *= sb; }virtual void Rotate(double nang) { angle += nang; }};class Circle :public BaseEllipse {private:double r;public:Circle(double x0=0, double y0=0, double r0=0) :BaseEllipse(x0, y0) { r = r0; }virtual double Area() const { return 3.14*r*r; }virtual void Scale(double sr) { r *= sr; }};
浙公网安备 33010602011771号