12.1 在例12.1程序基础上作一些修改。定义Point类,由Point类派生出Circle类,再由Circle类派生出Cylinder类。将类的定义部分分别作为3个头文件,对它们的成员函数的声明部分分别作为3个源文件,在主函数中用#include命令把它们包含进来,形成一个完整的程序,并上机运行。
头文件
Point.h
#include <iostream>
using namespace std;
class Point
{
public:
Point(double x=0, double y=0);
void setPoint(double, double);
double getX() const{return x;}
double getY() const{return y;}
friend ostream & operator<<(ostream &, const Point &);
protected:
double x, y;
};
Circle.h
class Circle: public Point
{
public:
Circle (double x=0, double y=0, double r=0);
void setRadius(double);
double getRadius() const;
double area() const;
friend ostream& operator<<(ostream &, const Circle &);
protected:
double radius;
};
Cylinder.h
class Cylinder: public Circle
{
public:
Cylinder(double x=0, double y=0, double r=0, double h=0);
void setHeight(double);
double getHeight() const;
double area() const;
double volume() const;
friend ostream& operator<<(ostream &, const Cylinder &);
protected:
double height;
};
源文件
Point.cpp
#include <iostream>
#include "Point.h"
using namespace std;
Point::Point(double a, double b)
{
x=a; y=b;
}
void Point::setPoint(double a, double b)
{
x=a; y=b;
}
ostream& operator<<(ostream &output, const Point &p)
{
output<<"["<<p.x<<", "<<p.y<<"]"<<endl;
return output;
}
Circle.cpp
#include <iostream>
#include "Point.h"
#include "Circle.h"
using namespace std;
Circle::Circle(double a, double b, double r): Point(a, b), radius(r){}
void Circle::setRadius(double r){radius=r;}
double Circle::getRadius() const { return radius;}
double Circle::area() const {return 3.14159*radius*radius;}
ostream& operator<<(ostream &output, const Circle &c)
{
output<<"Center=["<<c.x<<", "<<c.y<<"], r="<<c.radius<<", area="<<c.area()<<endl;
return output;
}
Cylinder.cpp
#include <iostream>
#include "Point.h"
#include "Circle.h"
#include "Cylinder.h"
using namespace std;
Cylinder::Cylinder(double a, double b, double r, double h)
:Circle(a, b, r), height(h){}
void Cylinder::setHeight(double h) {height=h;}
double Cylinder::getHeight() const {return height;}
double Cylinder::area() const {return 2*Circle::area()+2*3.14159*radius*height;}
double Cylinder::volume() const {return Circle::area()*height;}
ostream& operator<<(ostream &output, const Cylinder &cy)
{
output<<"Center=["<<cy.x<<", "<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height
<<"\narea="<<cy.area()<<", volume="<<cy.volume()<<endl;
return output;
}
main函数
#include <iostream>
#include "Point.h"
#include "Circle.h"
#include "Cylinder.h"
using namespace std;
int main()
{
Cylinder cy1(3.5, 6.4, 5.2, 10);
cout<<"\noriginal cylinder:\nx="<<cy1.getX()<<", y="<<cy1.getY()<<", r="
<<cy1.getRadius()<<", h="<<cy1.getHeight()<<"\narea="<<cy1.area()
<<", volume="<<cy1.volume()<<endl;
cy1.setHeight(15);
cy1.setRadius(7.5);
cy1.setPoint(5, 5);
cout<<"\nnew cylinder:\n"<<cy1;
Point &pRef=cy1;
cout<<"\npRef as a Point:"<<pRef;
Circle &cRef=cy1;
cout<<"\ncRef as a Circle:"<<cRef;
system("pause");
return 0;
}
12.2 请比较函数重载和虚函数在概念上和使用方式有什么区别
概念方面:
函数重载的定义是:在同一作用域(如:类)中,几个函数名字相同但参数列表(参数类型,参数个数)不全相同。
虚函数的定义是:在基类中用关键词“virtual”声明成员函数,然后在派生类中正式定义或重新定义此函数,其中要求函数名、函数类型、参数类型和个数必须与基类虚函数相同。
所以函数重载和虚函数在概念上的最大差别在于函数重载针对某个类里面的同名函数而言,而虚函数是针对基类和派生类之间同名函数而言。
在使用方式方面:
函数重载需要注意作用域,在内层作用域中声明的重载函数会隐藏外层作用域中的同名函数;在调用重载函数时要注意参数匹配,注意“无匹配”和“二义性调用”等问题。
虚函数只能用virtual声明类的成员函数,不能把类外的普通函数作为虚函数,它只能用于类的继承层次结构中;在同一类族中不能再定义一个非virtual的但与虚函数具有相同参数(类型和个数)和返回类型的同名函数。
12.3 在例12.3的基础上作以下修改,并作必要的讨论。
(1) 把构造函数修改为带参数的函数,在建立对象时初始化。
#include<iostream>
using namespace std;
class Point
{
public:
Point(int a, int b) {
a = x;
b = y;
}
~Point()
{
cout << "executing Point destructor" << endl;
}
private:
int x;
int y;
};
class Circle :public Point
{
public:
Circle(int a, int b, int c) :Point(a, b), radus(c) {
}
~Circle()
{
cout << "executing Circle destructor" << endl;
}
private:
int radus;
};
int main()
{
Point* p = new Circle(2.5, 1.8, 4.5);
delete p;
return 0;
}
(2) 先不将析构函数声明为virtual,在main函数中另设一个指向Circle类对象的指针变量,使它指向grad1。运行程序,分析结果。
#include<iostream>
using namespace std;
class Point
{
public:
Point(int a, int b) {
a = x;
b = y;
}
~Point()
{
cout << "executing Point destructor" << endl;
}
private:
int x;
int y;
};
class Circle :public Point
{
public:
Circle(int a, int b, int c) :Point(a, b), radus(c) {
}
~Circle()
{
cout << "executing Circle destructor" << endl;
}
private:
int radus;
};
int main()
{
Point* p = new Circle(2.5, 1.8, 4.5);
Circle* pt = new Circle(2.5, 1.8, 4.5);
delete pt;
return 0;
}
(3) 不作第(2)点的修改而将析构函数声明为virtual,运行程序,分析结果。
#include<iostream>
using namespace std;
class Point
{
public:
Point(int a, int b) {
a = x;
b = y;
}
virtual ~Point()
{
cout << "executing Point destructor" << endl;
}
private:
int x;
int y;
};
class Circle :public Point
{
public:
Circle(int a, int b, int c) :Point(a, b), radus(c) {
}
~Circle()
{
cout << "executing Circle destructor" << endl;
}
private:
int radus;
};
int main()
{
Point* p = new Circle(2.5, 1.8, 4.5);
delete p;
return 0;
}
12.4 编写一个程序,声明抽象基类Shape,由它派生出3个派生类:Circle(圆形)、Rectangle(矩形)、Triangle(三角形),用一个函数printArea分别输出以上三者的面积,3个图形的数据在定义对象时给定。
#include <iostream>
using namespace std;
//定义抽象基类Shape
class Shape
{
public:
virtual double area() const = 0; //纯虚函数
};
//定义Circle类
class Circle :public Shape
{
public:
Circle(double r) :radius(r) {} //结构函数
virtual double area() const { return 3.14159 * radius * radius; }; //定义虚函数
protected:
double radius; //半径
};
//定义Rectangle类
class Rectangle :public Shape
{
public:
Rectangle(double w, double h) :width(w), height(h) {} //结构函数
virtual double area() const { return width * height; } //定义虚函数
protected:
double width, height; //宽与高
};
class Triangle :public Shape
{
public:
Triangle(double w, double h) :width(w), height(h) {} //结构函数
virtual double area() const { return 0.5 * width * height; } //定义虚函数
protected:
double width, height; //宽与高
};
//输出面积的函数
void printArea(const Shape& s)
{
cout << s.area() << endl; //输出s的面积
}
int main()
{
Circle circle(2.5); //建立Circle类对象circle
cout << "area of circle =";
printArea(circle); //输出circle的面积
Rectangle rectangle(2.5, 4); //建立Rectangle类对象rectangle
cout << "area of rectangle =";
printArea(rectangle); //输出rectangle的面积
Triangle triangle(5, 6); //建立Triangle类对象
cout << "area of triangle =";
printArea(triangle); //输出triangle的面积
return 0;
}
12.5 写一个程序,定义抽象基类Shape,由它派生出5个派生类:Circle、Square、Rectangle、Tarpezoid、Triangle。用虚函数分别计算几种图形面积,并求它们的和。要求用基类指针数组,使它的每一个元素指向一个派生类对象。
#include <iostream>
using namespace std;
//定义抽象基类Shape
class Shape
{
public:
virtual double area() const = 0; //纯虚函数
};
//定义Circle(圆形)类
class Circle :public Shape
{
public:
Circle(double r) :radius(r) {} //结构函数
virtual double area() const { return 3.14159 * radius * radius; }; //定义虚函数
protected:
double radius; //半径
};
//定义Square(正方形)类
class Square :public Shape
{
public:
Square(double s) :side(s) {} //结构函数
virtual double area() const { return side * side; } //定义虚函数
protected:
double side;
};
//定义Rectangle(矩形)类
class Rectangle :public Shape
{
public:
Rectangle(double w, double h) :width(w), height(h) {} //结构函数
virtual double area() const { return width * height; } //定义虚函数
protected:
double width, height; //宽与高
};
//定义Trapezoid(梯形)类
class Trapezoid :public Shape
{
public:
Trapezoid(double t, double b, double h) :top(t), bottom(t), height(h) {} //结构函数
virtual double area() const { return 0.5 * (top + bottom) * height; } //定义虚函数
protected:
double top, bottom, height; //上底、下底与高
};
//定义Triangle(三角形)类
class Triangle :public Shape
{
public:
Triangle(double w, double h) :width(w), height(h) {} //结构函数
virtual double area() const { return 0.5 * width * height; } //定义虚函数
protected:
double width, height; //宽与高
};
int main()
{
Circle circle(12.6); //建立Circle类对象circle
Square square(3.5); //建立Square类对象square
Rectangle rectangle(4.5, 8.4); //建立Rectangle类对象rectangle
Trapezoid trapezoid(2.0, 4.5, 3.2); //建立Trapezoid类对象trapezoid
Triangle triangle(4.5, 8.4); //建立Triangle类对象
Shape* pt[5] = { &circle,&square,&rectangle,&trapezoid,&triangle };
//定义基类指针数组pt,使它每一个元素指向一个派生类对象
double areas = 0.0; //areas为总面积
for (int i = 0; i < 5; i++)
{
areas = areas + pt[i]->area();
}
cout << "totol of all areas=" << areas << endl; //输出总面积
return 0;
}