别调用他们的成员虚函数picture类。注意要把每个类的特征用最简单的方式表示出来。这个实验是一个很 综合的编程设计,希望大家先自己考虑考虑,可以参考第一个实验中的一些设计思想。 实验源代码: 程序的头文件我们放在graphic.h中 //定义point类 #include <iostream.h> #include <conio.h> #include <math.h> class point { private: int x,y; public; point() { x=0; y=0; } point(int x_pos,int y_pos) { x=x_pos; y=y_pos; } point(const Point &p) { x=p.x; y=p.y; } int getx() { return x; } int gety() { return y; } }; 说明:类point包含了两个定义点的基本元素x坐标和y坐标,还有两个获得各坐标的成员函数getx()和 gety()。它的构造函数有三个,分别实现不同的功能。point()是给点赋0值。由于没有开辟内存,所以析构 函数可以没有。 //这是一个枚举,white至cyan分别代 //表了0至7的值 enum ColorType{White,Black,Red,Green,Blue Yellow,Magenta,Cyan}; //为图形形状定义Shape基类 class Shape { protected: ColorType color; public: Shape(ColorType c) { color=c; } virtual void draw(); { cout<<"Draw not overridden"<<endl; exit(1); } }; 说明: Shape类给出了以后要定义的图形的公有特征。它用构造函数来设置颜色,并提供一个显示形状 的虚函数Draw()。当图形不同时,Draw()的实现也有所不同(例如以半径和圆心作圆就与按长宽来作矩形 不同)。基类只给出Draw()的调用形式,具体实现留给派生类。由于基类有一个语句exit(1),如果直接使用 基类的Draw(),就要给出错误的信息。 从Shape类我们派生一个直线line类: class Line { private: point start,end; public: Line(ColorType c,point s,point e): Shape(ColorType c) { start=s; end=e; } virtual void draw() { cout<<"This is a line!"<<endl; cout<<"Its start point is (" <<start.x<<","<<start.y<< ")。"<<endl; cout<<"Its end point is (" <<end.x<<","<<end.y<< ")。"<<endl; //这里可以加一些别的语句 } }; 说明:Line包含两个定义起点和终止点的数据成员。它的构造函数接收两个点并把它赋给start和end成员 的point,还通过成员列表的形式接收一个传给基类Shape构造函数的颜色值。Line必须再次定义Draw(), 这里只给出了示意语句,大家可以通过调用图形库函数来完成画线、画矩形和画圆的功能,这里就不详细 述说了。 下面定义的Rectangle类和Circle类与Line类是类似的,它们都定义了几个数据成员、构造函数和虚 函数Draw()。 class Rectangle:public Shape { private: point upperleft; point lowerright; public: Rectangle(ColorType c,point ul,point lr) :Shape(ColorType c) { upperleft=ul; lowerright=lr; } virtual void Draw() { cout<<"This is a rectangle!"<<endl; cout<<"Its upperleft point is ("<< upperleft.x<<","<<upperleft.y<< ")。"<<endl; cout<<"Its lowerright point is ("<< lowerright.x<<","<<lowerright.y<< ")。"<<endl; // 其他语句。 } };
class Circle:public Shape { private: point center; //圆心 int radius; //半径 public: Circle(ColorType c,point cent,int rad) :Shape(ColorType c) { center=cent; radius=rad; } virtual void Draw() { cout<<"This is a circle!"<<endl; cout<<"Its center is ("<< center.x<<","<<center.y <<")。"<<endl; cout<<"Its radius is "<<radius <<"。"<<endl; //其他语句 } }; 最后我们还要设计一个Picture类,用来绘制这些图形 class Picture { private: Shape *s[6]; public: Picture(Shape* s1, Shape* s2 Shape* s3, Shape* s4, Shape* s5 Shape* s6) { s[0]=s1;s[1]=s2;s[2]=s3; s[3]=s4;s[4]=s5;s[5]=s6; } void paint() { for(int i=0;i<6;i++) s[i]->Draw(); } }; 说明:Picture类中包含了6个Shape指针的数组、一个构造函数和一个显示六个形状的paint() 函数。由于Draw()定义为虚函数,所以paint()在调用Draw()时,并不关心Draw()是由什么形状 的类来调用的,它只是要把这6个图形一一画出就可以了。 下面给出主程序,主程序我们放在graphic.cpp文件中。 void main() { Line l1(Red,point(1,1),point(250,300)); Line l1(White,point(3,5),point(100,200)); //定义了两条红、白直线 Circle c1(Blue,point(100,75),50); Circle c2(Green,point(50,200),20); //定义两个圆 Rectangle r1(Yellow,point(10,10),point(255,150)); Rectangle r2(Magenta,point(20,30),point (100,125)); //定义两个矩形 Picture p(&l1,&l2,&c1,&c2,&r1,&r2); p.paint(); } 说明:在程序中,我们生成了六个不同的图形对象,并把它传给了Picture对象的数组,当p调 用paint()方法时,也就通过for语句为每一个形状调用了Draw()方法。 最后的输出结果为: This is a line! Its start point is (1,1)。 Its end point is (250,300)。 This is a line! Its start point is (3,5)。 Its end point is (100,200)。
This is a circle! Its center is (100,75)。 Its radius is 50。 This is a circle! Its center is (50,200)。 Its radius is 20。
This is a rectangle! Its upperleft point is (10,10)。 Its lowerright point is (255,150)。 This is a rectangle! Its upperleft point is (20,30)。 Its lowerright point is (100,125)。 实验思考: (1) 大家可以定义在Shape类的基础上定义一个椭圆类,尽量用最好的方式表现这个椭 圆,并仿造上面的方法在虚函数Draw()中输出这个椭圆。 (2) 由于枚举数列只能表现数值,如本例中表现颜色时,只能出现数字,不能出现具体 的颜色,试编写一个函数,实现数字和颜色的转换,并把它在虚函数Draw()中表现 出来。 (3) 本例是通过paint()函数里的for循环,一次性全部调用了6个类的虚函数,这只能针对 本例而言,没有可移植性。大家可以在picture里再编写一个函数,可分别调用各个类的虚函数, 要用上指针或引用。
|