0%

C++语言程序设计(郑莉第五版)第八章课后习题代码实现

第八章 多态性

注:下述代码中省略了

1
2
#include <iostream>
using namespace std;

8-4 请编写一个计数器Counter类,对其重载运算符“+”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Counter {
private:
int num;
public:
Counter() :num(0) {}
Counter(int n) :num(n) {}
void SetNum(int n) {
num = n;
}
void show() {
cout << num << endl;
}
int operator +(Counter& c) {//重载“+”
return num + c.num;
}
};

8-5 编写一个哺乳动物类Mammal,再由此派生出狗类Dog,二者都声明speak()成员函数,该函数在基类中被声明为虚函数,声明一个Dog类的对象,通过此对象调用speak函数,观察运行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Mammal {
public:
virtual void speak() {
cout << "mammal sepak" << endl;

}
};

class Dog {
public:
void speak() {
cout << "dog speak" << endl;
}
};

int main() {
Mammal m1;
Dog d;
Mammal* m2 = &d;
m1.speak(); //mammal sepak
m2->speak(); //dog speak
d.speak(); //dog speak
}

8-6 请编写一个抽象类Shape,在此基础上派生出类Rectangle和Circle,二者都有计算对象面积的函数getArea()、计算对象周长的函数getPerim()。

抽象类Shape的声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Shape {
public:
virtual void getArea() const = 0;//纯虚常函数
virtual void getPerim() const = 0;//纯虚常函数
virtual ~Shape(){}//注意虚析构函数不要忘
private:
};
```

### 派生类Rectangle和Circle的声明

```cpp
//Rectangle中新增数据成员length和width,计算面积与周长时同样会用到这两个数据成员
class Rectangle :public Shape {
public:
Rectangle():length(0), width(0){}
Rectangle(double x, double y):length(x), width(y){}
virtual void getArea() const override {//覆盖Shape类getArea()函数
cout << "Rectangle's area is: " << length * width << endl;
}
virtual void getPerim() const override {//覆盖Shape类getPerim()函数
cout << "Rectangle's perim is: " << 2 * (length + width) << endl;
}
private:
double length, width;//分别代表长方形的长与宽
};

//Circle中新增数据成员radius,PI的值在类外定义为常量
const double PI = 3.1415926;
class Circle :public Shape {
public:
Circle() : radius(0) {}//构造函数
Circle(double r) : radius(r) {}//构造函数
virtual void getArea() const override {//覆盖Shape类getArea()函数
cout << "Circle's area is : " << PI * radius * radius << endl;
}
virtual void getPerim() const override {//覆盖Shape类getPerim()函数
cout << "Circle's perim is : " << 2 * PI * radius << endl;
}
private:
double radius;//代表圆的半径
};

main()函数测试

1
2
3
4
5
6
7
8
9
10
int main() {
Shape* shape[2];//抽象类不能实例化,但是可以定义一个抽象类的指针和引用,在此声明一个Shape类的指针数组
shape[0] = new Circle(2);//指针数组的第一个元素指向一个半径为2的Circle类
shape[1] = new Rectangle(2.5, 4);//指针数组的第二个元素指向一个长2.5、宽4的Rectangle类
for (int i = 0; i < 2; i++) {
shape[i]->getArea();//i = 0 : 12.5664; i = 1 : 10
shape[i]->getPerim();//i = 0 : 12.5664; i = 1 : 13
}
return 0;
}

8-7 对类Point重载“++”(自增)、“--”(自减)运算符,要求同时重载前缀和后缀形式。

题目中并没有指出对于Point类重载的自增/自减运算符要具体实现什么功能,在这里我将其实现为将对象的横纵坐标各加/减一

Point类的声明

注:由于类Point是本书示例中常用的一个类,我将其声明单独写在了一份头文件里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
class Point {
public:
Point() :x(0), y(0) {};
Point(double x, double y) :x(x), y(y) {};
double getx();
double gety();
void setx(double newx);
void sety(double newy);
Point& operator ++();//实现横纵坐标各加一(前置运算)
Point operator ++ (int);//实现横纵坐标各加一(后置运算)
Point& operator --();//实现横纵坐标各减一(前置运算)
Point operator -- (int);//实现横纵坐标各减一(后置运算)
friend Point operator + (Point p1, Point p2);//声明友元函数重载运算符“+”(在题8-10中用到)
void show();
private:
double x, y;
};

Point类的实现(自增/自减运算符重载的实现在这里定义)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "point.h"
#include<iostream>
using namespace std;
double Point::getx(){
return x;
}

double Point::gety(){
return y;
}

void Point::setx(double newx){
x = newx;
}

void Point::sety(double newy){
y = newy;
}

Point& Point::operator++(){//前置自增
setx(getx() + 1);//横坐标x加一
sety(gety() + 1);//纵坐标y加一
return * this;
}

Point Point::operator++(int){//后置自增
Point old = *this;//调用前置自增前先把值复制给Point对象old
++(*this);//调用前置自增
return old;
}

Point& Point::operator--(){//前置自减
setx(getx() - 1);//横坐标x减一
sety(gety() - 1);//纵坐标y减一
return *this;
}

Point Point::operator--(int){//后置自减
Point old = *this;//调用前置自减前先把值复制给Point对象old
--(*this);//调用前置自减
return old;
}

void Point::show(){
cout << "(" << x << "," << y << ")" << endl;
}

Point operator+(Point p1, Point p2)
{
return Point(p1.x + p2.x, p1.y + p2.y);
}

main()函数进行测试

1
2
3
4
5
6
7
8
9
#include"point.h"
int main() {
Point p(0, 0);//声明一个Point对象p,此时p的坐标为(0,0)
(p++).show();//此时p的坐标为(1,1),但输出的结果是(0,0)
(++p).show();//此时p的坐标为(2,2),但输出的结果是(2,2)
(p--).show();//此时p的坐标为(1,1),但输出的结果是(2,2)
(--p).show();//此时p的坐标为(0,0),但输出的结果是(0,0)
return 0;
}

8-8 定义一个基类BaseClass,从它派生出类DerivedClass。BaseClass有成员函数fn1()、fn2(),fn1()是虚函数;DerivedClass也有成员函数fn1()、fn2()。在主函数中声明一个DerivedClass的对象,分别用BaseClass和DerivedClass的指针指向DerivedClass的对象,并通过指针调用fn1()、fn2(),观察运行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class BaseClass {
public:
virtual void fn1() {
cout << "Base fn1()" << endl;
}
void fn2() {
cout << "Base fn2()" << endl;
}
};

class DerivedClass :public BaseClass {
public:
void fn1() {
cout << "Derived fn1()" << endl;
}
void fn2() {
cout << "Derived fn2()" << endl;
}
};

int main() {
DerivedClass DC;
BaseClass* bp = &DC;
DerivedClass* dp = &DC;
bp->fn1();//Derived fn1()
bp->fn2();//Base fn2()
dp->fn1();//Derived fn1()
dp->fn2();//Derived fn2()
return 0;
}

8-9 请编写程序定义一个基类BaseClass,从它派生出类DerivedClass。在BaseClass中声明虚析构函数,在主函数中将一个动态分配的DerivedClass的对象地址赋给一个BaseClass的指针,然后通过指针释放对象空间,观察程序运行过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//8_9
class BaseClass {
public:
virtual ~BaseClass() {
cout << "Destructing BaseClass..." << endl;
}
};

class DerivedClass :public BaseClass {
public:
~DerivedClass() {
cout << "Destructing DerivedClass..." << endl;
}
};

int main() {
BaseClass* bc = new DerivedClass;
delete bc;
//Destructing DerivedClass...
//Destructing BaseClass...
return 0;
}

8-10 编写程序定义类Point,有数据成员x,y,为其定义友元函数实现重载“+”。

此题目已在8-7中实现,参考8-7代码即可。