例12.1 先建立一个Point(点)类,包含数据成员x,y(坐标点)。以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高)。要求编写程序,重载运算符“<<”和“>>”,使之能用于输出以上类对象。
对于一个比较大的程序,应当分成若干步骤进行。先声明基类,再声明派生类,逐级进行,分步调试。
(1) 声明基类Point类
可写出声明基类Point的部分如下:
#include <iostream>
//声明类Point
classPoint
{public:
Point(floatx=0,floaty=0);//有默认参数的构造函数
voidsetPoint(float,float); //设置坐标值
floatgetX( ) const{returnx;} //读x坐标
floatgetY( ) const{returny;} //读y坐标
friendostream & operator<<(ostream &,constPoint &);//重载运算符“<<”
protected: //受保护成员
floatx,y;
};
//下面定义Point类的成员函数
//Point的构造函数
Point::Point(floata,floatb) //对x,y初始化
{x=a;y=b;}
//设置x和y的坐标值
voidPoint::setPoint(floata,floatb) //为x,y赋新值
{x=a;y=b;}
//重载运算符“<<”,使之能输出点的坐标
ostream & operator<<(ostream &output,constPoint &p)
{output<<"["<<p.x<<","<<p.y<<"]"<<endl;
returnoutput;
}
以上完成了基类Point类的声明。
现在要对上面写的基类声明进行调试,检查它是否有错,为此要写出main函数。实际上它是一个测试程序。
intmain( )
{Point p(3.5,6.4);//建立Point类对象p
cout<<"x="<<p.getX( )<<",y="<<p.getY( )<<endl;//输出p的坐标值
p.setPoint(8.5,6.8); //重新设置p的坐标值
cout<<"p(new):"<<p<<endl; //用重载运算符“<<”输出p点坐标
}
程序编译通过,运行结果为
x=3.5,y=6.4
p(new):[8.5,6.8]
测试程序检查了基类中各函数的功能,以及运算符重载的作用,证明程序是正确的。
(2) 声明派生类Circle
在上面的基础上,再写出声明派生类Circle的部分:
classCircle:publicPoint//circle是Point类的公用派生类
{public:
Circle(floatx=0,floaty=0,floatr=0); //构造函数
voidsetRadius(float); //设置半径值
floatgetRadius( ) const; //读取半径值
floatarea ( ) const; //计算圆面积
friendostream &operator<<(ostream &,constCircle &);//重载运算符“<<”
private:
floatradius;
};
//定义构造函数,对圆心坐标和半径初始化
Circle::Circle(floata,floatb,floatr):Point(a,b),radius(r){ }
//设置半径值
voidCircle::setRadius(floatr)
{radius=r;}
//读取半径值
floatCircle::getRadius( ) const{returnradius;}
//计算圆面积
floatCircle::area( ) const
{return3.14159*radius*radius;}
//重载运算符“<<”,使之按规定的形式输出圆的信息
ostream &operator<<(ostream &output,constCircle &c)
{output<<"Center=["<<c.x<<","<<c.y<<"],r="<<c.radius<<",area="<<c.area( )<<endl;
returnoutput;
}为了测试以上Circle类的定义,可以写出下面的主函数:intmain( )
{Circle c(3.5,6.4,5.2);//建立Circle类对象c,并给定圆心坐标和半径
cout<<"original circle:\\nx="<<c.getX()<<", y="<<c.getY()<<", r="<<c.getRadius( )
<<", area="<<c.area( )<<endl; //输出圆心坐标、半径和面积
c.setRadius(7.5); //设置半径值
c.setPoint(5,5); //设置圆心坐标值x,y
cout<<"new circle:\\n"<<c; //用重载运算符“<<”输出圆对象的信息
Point &pRef=c; //pRef是Point类的引用变量,被c初始化
cout<<"pRef:"<<pRef; //输出pRef的信息
return0;
}程序编译通过,运行结果为original circle:(输出原来的圆的数据)
x=3.5, y=6.4, r=5.2, area=84.9486
newcircle: (输出修改后的圆的数据)
Center=[5,5], r=7.5, area=176.714
pRef:[5,5] (输出圆的圆心“点”的数据)
(3) 声明Circle的派生类Cylinder
前面已从基类Point派生出Circle类,现在再从Circle派生出Cylinder类。
classCylinder:publicCircle// Cylinder是Circle的公用派生类
{public:
Cylinder (floatx=0,floaty=0,floatr=0,floath=0);//构造函数
voidsetHeight(float); //设置圆柱高
floatgetHeight( ) const; //读取圆柱高
floatarea( ) const; //计算圆表面积
floatvolume( ) const; //计算圆柱体积
friendostream& operator<<(ostream&,constCylinder&);//重载运算符“<<”
protected:
floatheight; //圆柱高
};
//定义构造函数
Cylinder::Cylinder(floata,floatb,floatr,floath)
:Circle(a,b,r),height(h){}
//设置圆柱高
voidCylinder::setHeight(floath){height=h;}
//读取圆柱高
floatCylinder::getHeight( ) const{returnheight;}
//计算圆表面积
floatCylinder::area( ) const
{ return2*Circle::area( )+2*3.14159*radius*height;}
//计算圆柱体积
floatCylinder::volume() const
{returnCircle::area()*height;}
//重载运算符“<<”
ostream &operator<<(ostream &output,constCylinder& cy)
{output<<"Center=["<<cy.x<<","<<cy.y<<"],r="<<cy.radius<<",h="<<cy.height
<<"\\narea="<<cy.area( )<<", volume="<<cy.volume( )<<endl;
returnoutput;
}
可以写出下面的主函数:
intmain( )
{Cylinder cy1(3.5,6.4,5.2,10);//定义Cylinder类对象cy1
cout<<"\\noriginal cylinder:\\nx="<<cy1.getX( )<<", y="<<cy1.getY( )<<", r="
<<cy1.getRadius( )<<", h="<<cy1.getHeight( )<<"\\narea="<<cy1.area()
<<",volume="<<cy1.volume()<<endl;//用系统定义的运算符“<<”输出cy1的数据
cy1.setHeight(15); //设置圆柱高
cy1.setRadius(7.5); //设置圆半径
cy1.setPoint(5,5); //设置圆心坐标值x,y
cout<<"\\nnew cylinder:\\n"<<cy1; //用重载运算符“<<”输出cy1的数据
Point &pRef=cy1; //pRef是Point类对象的引用变量
cout<<"\\npRef as a Point:"<<pRef; //pRef作为一个“点”输出
Circle &cRef=cy1; //cRef是Circle类对象的引用变量
cout<<"\\ncRef as a Circle:"<<cRef; //cRef作为一个“圆”输出
return0;
}
运行结果如下:
original cylinder: (输出cy1的初始值)
x=3.5, y=6.4, r=5.2, h=10 (圆心坐标x,y。半径r,高h)
area=496.623, volume=849.486 (圆柱表面积area和体积volume)
newcylinder: (输出cy1的新值)
Center=[5,5], r=7.5, h=15 (以[5,5]形式输出圆心坐标)
area=1060.29, volume=2650.72 (圆柱表面积area和体积volume)
pRef as a Point:[5,5] (pRef作为一个“点”输出)
cRef as a Circle: Center=[5,5], r=7.5, area=176.714(cRef作为一个“圆”输出)
例12.2 基类与派生类中有同名函数。
在下面的程序中Student是基类,Graduate是派生类,它们都有display这个同名的函数。
#include <iostream>
#include <string>
usingnamespacestd;
//声明基类Student
classStudent
{public:
Student(int, string,float);//声明构造函数
voiddisplay( ); //声明输出函数
protected: //受保护成员,派生类可以访问
intnum;
string name;
floatscore;
};
//Student类成员函数的实现
Student::Student(intn, string nam,floats) //定义构造函数
{num=n;name=nam;score=s;}
voidStudent::display( ) //定义输出函数
{cout<<"num:"<<num<<"\\nname:"<<name<<"\\nscore:"<<score<<"\\n\\n";}
//声明公用派生类Graduate
classGraduate:publicStudent
{public:
Graduate(int, string, float, float); //声明构造函数
voiddisplay( ); //声明输出函数
private:
floatpay;
};
// Graduate类成员函数的实现
voidGraduate::display( ) //定义输出函数
{cout<<"num:"<<num<<"\\nname:"<<name<<"\\nscore:"<<score<<"\\npay="<<pay<<endl;}
Graduate::Graduate(intn, string nam,floats,floatp):Student(n,nam,s),pay(p){ }
//主函数
intmain()
{Student stud1(1001,"Li",87.5); //定义Student类对象stud1
Graduate grad1(2001,"Wang",98.5,563.5); //定义Graduate类对象grad1
Student *pt=&stud1; //定义指向基类对象的指针变量pt
pt->display( );
pt=&grad1;
pt->display( );
return0;
}
例12.3 基类中有非虚析构函数时的执行情况。
为简化程序,只列出最必要的部分。
#include <iostream>
usingnamespacestd;
classPoint//定义基类Point类
{public:
Point( ){ } //Point类构造函数
~Point(){cout<<"executing Point destructor"<<endl;}//Point类析构函数
};
classCircle:publicPoint //定义派生类Circle类
{public:
Circle( ){ } //Circle类构造函数
~Circle( ){cout<<"executing Circle destructor"<<endl;}//Circle类析构函数
private:
intradius;
};
intmain( )
{ Point *p=newCircle; //用new开辟动态存储空间
deletep; //用delete释放动态存储空间
return0;
}
例12.4 虚函数和抽象基类的应用。
在本章例12.1介绍了以Point为基类的点—圆—圆柱体类的层次结构。现在要对它进行改写,在程序中使用虚函数和抽象基类。类的层次结构的顶层是抽象基类Shape(形状)。Point(点), Circle(圆), Cylinder(圆柱体)都是Shape类的直接派生类和间接派生类。
下面是一个完整的程序,为了便于阅读,分段插入了一些文字说明。
程序如下:
第(1)部分
#include <iostream>
usingnamespacestd;
//声明抽象基类Shape
classShape
{public:
virtualfloatarea( ) const{return0.0;}//虚函数
virtualfloatvolume() const{return0.0;} //虚函数
virtualvoidshapeName() const=0; //纯虚函数
};
第(2)部分
//声明Point类
classPoint:publicShape//Point是Shape的公用派生类
{public:
Point(float=0,float=0);
voidsetPoint(float,float);
floatgetX( ) const{returnx;}
floatgetY( ) const{returny;}
virtualvoidshapeName( ) const{cout<<"Point:";} //对虚函数进行再定义
friendostream & operator<<(ostream &,constPoint &);
protected:
floatx,y;
};
//定义Point类成员函数
Point::Point(floata,floatb)
{x=a;y=b;}
voidPoint::setPoint(floata,floatb)
{x=a;y=b;}
ostream & operator<<(ostream &output,constPoint &p)
{output<<"["<<p.x<<","<<p.y<<"]";
returnoutput;
}
第(3)部分
//声明Circle类
classCircle:publicPoint
{public:
Circle(floatx=0,floaty=0,floatr=0);
voidsetRadius(float);
floatgetRadius( ) const;
virtualfloatarea( ) const;
virtualvoidshapeName( ) const{cout<<"Circle:";}//对虚函数进行再定义
friendostream &operator<<(ostream &,constCircle &);
protected:
floatradius;
};
//声明Circle类成员函数
Circle::Circle(floata,floatb,floatr):Point(a,b),radius(r){ }
voidCircle::setRadius(floatr):radius(r){ }
floatCircle::getRadius( ) const{returnradius;}
floatCircle::area( ) const{return3.14159*radius*radius;}
ostream &operator<<(ostream &output,constCircle &c)
{output<<"["<<c.x<<","<<c.y<<"], r="<<c.radius;
returnoutput;
}
第(4)部分
//声明Cylinder类
classCylinder:publicCircle
{public:
Cylinder (floatx=0,floaty=0,floatr=0,floath=0);
voidsetHeight(float);
virtualfloatarea( ) const;
virtualfloatvolume( ) const;
virtualvoidshapeName( ) const{cout<<"Cylinder:";}//对虚函数进行再定义
friendostream& operator<<(ostream&,constCylinder&);
protected:
floatheight;
};
//定义Cylinder类成员函数
Cylinder::Cylinder(floata,floatb,floatr,floath)
:Circle(a,b,r),height(h){ }
voidCylinder::setHeight(floath){height=h;}
floatCylinder::area( ) const
{ return2*Circle::area( )+2*3.14159*radius*height;}
floatCylinder::volume( ) const
{returnCircle::area( )*height;}
ostream &operator<<(ostream &output,constCylinder& cy)
{output<<"["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height;
returnoutput;
}
第(5)部分
//main函数
intmain( )
{Point point(3.2,4.5);//建立Point类对象point
Circle circle(2.4,1.2,5.6); //建立Circle类对象circle
Cylinder cylinder(3.5,6.4,5.2,10.5); //建立Cylinder类对象cylinder
point.shapeName(); //静态关联
cout<<point<<endl;
circle.shapeName(); //静态关联
cout<<circle<<endl;
cylinder.shapeName(); //静态关联
cout<<cylinder<<endl<<endl;
Shape *pt; //定义基类指针
pt=&point; //指针指向Point类对象
pt->shapeName( ); //动态关联
cout<<"x="<<point.getX( )<<",y="<<point.getY( )<<"\\narea="<<pt->area( )
<<"\\nvolume="<<pt->volume()<<"\\n\\n";
pt=&circle; //指针指向Circle类对象
pt->shapeName( ); //动态关联
cout<<"x="<<circle.getX( )<<",y="<<circle.getY( )<<"\\narea="<<pt->area( )
<<"\\nvolume="<<pt->volume( )<<"\\n\\n";
pt=&cylinder; //指针指向Cylinder类对象
pt->shapeName( ); //动态关联
cout<<"x="<<cylinder.getX( )<<",y="<<cylinder.getY( )<<"\\narea="<<pt->area( )
<<"\\nvolume="<<pt->volume( )<<"\\n\\n";
return0;
}