本实例来自《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 function
virtual 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; }
};
时间: 2024-12-24 23:26:30