Skip to content

Commit

Permalink
update ch18
Browse files Browse the repository at this point in the history
  • Loading branch information
applenob committed Apr 27, 2019
1 parent 21ba988 commit a475fa4
Show file tree
Hide file tree
Showing 4 changed files with 367 additions and 25 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ C++ Primer 中文版第5版学习仓库,包括**笔记**和**课后练习答
- 第 IV 部分 : 高级主题
- 第17章 : 标准库与特殊设施 [笔记](https://github.com/applenob/Cpp_Primer_Practice/tree/master/notes/ch17.md) [练习](https://github.com/applenob/Cpp_Primer_Practice/tree/master/excersize/ch17.md)
- 第18章 : 用于大型程序的工具 [笔记](https://github.com/applenob/Cpp_Primer_Practice/tree/master/notes/ch18.md) [练习](https://github.com/applenob/Cpp_Primer_Practice/tree/master/excersize/ch18.md)
- 第19章 : 特殊工具与技术 [笔记](https://github.com/applenob/Cpp_Primer_Practice/tree/master/notes/ch19.md) [练习](https://github.com/applenob/Cpp_Primer_Practice/tree/master/excersize/ch19.md)

- 第19章 : 特殊工具与技术 [笔记](https://github.com/applenob/Cpp_Primer_Practice/tree/master/notes/ch19.md) [练习](https://github.com/applenob/Cpp_Primer_Practice/tree/master/excersize/ch19.md)
## 参考

- [C++ Primer 5 Answers(C++11/14)](https://github.com/Mooophy/Cpp-Primer)
- [《C++ Primer》第五版中文版习题答案](https://github.com/huangmingchuan/Cpp_Primer_Answers)
178 changes: 155 additions & 23 deletions excersize/ch18.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
## 练习18.1

> 在下列 throw 语句中异常对象的类型是什么?
> 在下列 `throw` 语句中异常对象的类型是什么?
```cpp
(a) range_error r("error");
throw r;
(b) exception *p = &r;
throw *p;
```
解:
- (a): `range_error`
- (b): `exception`
## 练习18.2
> 当在指定的位置发生了异常时将出现什么情况?
Expand All @@ -21,13 +27,47 @@ void exercise(int *b, int *e)
}
```

解:

指针`p`指向的内容不会被释放,将造成内存泄漏。

## 练习18.3

> 要想让上面的代码在发生异常时能正常工作,有两种解决方案。请描述这两种方法并实现它们。
解:

方法一:不使用指针,使用对象:

```cpp
struct intArray
{
intArray() : p(nullptr) { }
explicit intArray(std::size_t s):
p(new int[s]) { }


~intArray()
{
delete[] p;
}

// data meber
int *p;
};

intArray p(v.size());
```
方法二:使用智能指针:
```cpp
std::shared_ptr<int> p(new int[v.size()], [](int *p) { delete[] p; });
```

## 练习18.4

> 查看图18.1所示的继承体系,说明下面的 try 块有何错误并修改它。
> 查看图18.1所示的继承体系,说明下面的 `try` 块有何错误并修改它。
```cpp
try {
// 使用 C++ 标准库
Expand All @@ -38,19 +78,37 @@ try {
} catch (overflow_error eobj) { /* ... */ }
```
解:
细化的异常类型应该写在前面:
```cpp
try {
// 使用 C++ 标准库
} catch (overflow_error eobj) {
// ...
} catch (const runtime_error &re) {
// ...
} catch (exception) { /* ... */ }
```

## 练习18.5

> 修改下面的main函数,使其能捕获图18.1所示的任何异常类型:
> 修改下面的`main`函数,使其能捕获图18.1所示的任何异常类型:
```cpp
int main(){
// 使用 C++标准库
}
```
处理代码应该首先打印异常相关的错误信息,然后调用 abort 终止函数。
处理代码应该首先打印异常相关的错误信息,然后调用 `abort` 终止函数。

解:


## 练习18.6

> 已知下面的异常类型和 catch 语句,书写一个 throw 表达式使其创建的异常对象能被这些catch语句捕获
> 已知下面的异常类型和 `catch` 语句,书写一个 `throw` 表达式使其创建的异常对象能被这些 `catch` 语句捕获
```cpp
(a) class exceptionType { };
catch(exceptionType *pet) { }
Expand All @@ -59,37 +117,71 @@ int main(){
catch(EXCPTYPE) { }
```
解:
```cpp
(a): throw exceptionType();
(b): throw expection();
(c): EXCPTYPE e = 1; throw e;
```

## 练习18.7

> 根据第16章的介绍定义你自己的Blob 和 BlobPtr,注意将构造函数写成函数try语句块。
> 根据第16章的介绍定义你自己的 `Blob``BlobPtr`,注意将构造函数写成函数`try`语句块。
解:


## 练习18.8

> 回顾你之前编写的各个类,为它们的构造函数和析构函数添加正确的异常说明。如果你认为某个析构函数可能抛出异常,尝试修改代码使得该析构函数不会抛出异常。
解:


## 练习18.9

> 定义本节描述的书店程序异常类,然后为 Sales_data 类重新编写一个复合赋值运算符并令其抛出一个异常。
> 定义本节描述的书店程序异常类,然后为 `Sales_data` 类重新编写一个复合赋值运算符并令其抛出一个异常。
## 练习18.10

> 编写程序令其对两个 ISBN 编号不相同的对象执行 Sales_data 的加法运算。为该程序编写两个不同的版本:一个处理异常,另一个不处理异常。观察并比较这两个程序的行为,用心体会当出现了一个未被捕获的异常时程序会发生什么情况。
> 编写程序令其对两个 `ISBN` 编号不相同的对象执行 `Sales_data` 的加法运算。为该程序编写两个不同的版本:一个处理异常,另一个不处理异常。观察并比较这两个程序的行为,用心体会当出现了一个未被捕获的异常时程序会发生什么情况。
解:


## 练习18.11

> 为什么 what 函数不应该抛出异常?
> 为什么 `what` 函数不应该抛出异常?
解:


## 练习18.12

> 将你为之前各章练习编写的程序放置在各自的命名空间中。也就是说,命名空间chapter15包含Query程序的代码,命名空间chapter10包含TextQuery的代码;使用这种结构重新编译Query代码实例。
> 将你为之前各章练习编写的程序放置在各自的命名空间中。也就是说,命名空间chapter15包含`Query`程序的代码,命名空间chapter10包含`TextQuery`的代码;使用这种结构重新编译`Query`代码实例。
解:


## 练习18.13

> 什么时候应该使用未命名的命名空间?
解:

需要定义一系列静态的变量的时候。

参考:https://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions

## 练习18.14

> 假设下面的operator*声明的是嵌套的命名空间 mathLib::MatrixLib 的一个成员:
> 假设下面的 `operator*` 声明的是嵌套的命名空间 `mathLib::MatrixLib` 的一个成员:
```cpp
namespace mathLib {
namespace MatrixLib {
Expand All @@ -101,13 +193,31 @@ namespace mathLib {
```
请问你应该如何在全局作用域中声明该运算符?
解:
```cpp
mathLib::MatrixLib::matrix mathLib::MatrixLib::operator* (const mathLib::MatrixLib::matrix &, const mathLib::MatrixLib::matrix &);
```

## 练习18.15

> 说明 using 指示与 using 声明的区别。
> 说明 `using` 指示与 `using` 声明的区别。

解:

- 一条`using`声明语句一次只引入命名空间的一个成员。
- `using` 指示使得某个特定的命名空间中所有的名字都可见。

有点像python中的`import`:

```python
from lib import func
from lib import *
```

## 练习18.16

> 假定在下面的代码中标记为“位置1”的地方是对命名空间 Exercise中所有成员的using声明,请解释代码的含义。如果这些using声明出现在“位置2”又会怎样呢?将using声明变为using指示,重新回答之前的问题。
> 假定在下面的代码中标记为“位置1”的地方是对命名空间 Exercise 中所有成员的`using`声明,请解释代码的含义。如果这些`using`声明出现在“位置2”又会怎样呢?`using`声明变为`using`指示,重新回答之前的问题。
```cpp
namespace Exercise {
int ivar = 0;
Expand All @@ -125,13 +235,21 @@ void main() {
}
```
解:
## 练习18.17
> 实际编写代码检验你对上一题的回答是否正确。
解:
## 练习18.18
> 已知有下面的 swap 的典型定义,当 mem1 是一个 string 时程序使用 swap 的哪个版本?如果 mem1 是 int 呢?说明在这两种情况下名字查找的过程。
> 已知有下面的 `swap` 的典型定义,当 `mem1` 是一个 `string` 时程序使用 `swap` 的哪个版本?如果 `mem1``int` 呢?说明在这两种情况下名字查找的过程。
```cpp
void swap(T v1, T v2)
{
Expand All @@ -141,13 +259,21 @@ void swap(T v1, T v2)
}
```

解:

`std::swap`是一个模板函数,如果是`string`会找到`string`版本;反之如果是`int`会找到`int`版本。

## 练习18.19

> 如果对 swap 的调用形如 std::swap(v1.mem1, v2.mem1) 将会发生什么情况?
> 如果对 `swap` 的调用形如 `std::swap(v1.mem1, v2.mem1)` 将会发生什么情况?

解:

会直接调用`std`版的`swap`,但对后面的调用无影响。

## 练习18.20

> 在下面的代码中,确定哪个函数与compute调用匹配。列出所有候选函数和可行函数,对于每个可行函数的实参与形参的匹配过程来说,发生了哪种类型转换?
> 在下面的代码中,确定哪个函数与`compute`调用匹配。列出所有候选函数和可行函数,对于每个可行函数的实参与形参的匹配过程来说,发生了哪种类型转换?
```cpp
namespace primerLib {
void compute();
Expand All @@ -163,9 +289,14 @@ void f()
}
```
解:
## 练习18.21
> 解释下列声明的含义,在它们当作存在错误吗?如果有,请指出来并说明错误的原因。
```cpp
(a) class CADVehicle : public CAD, Vehicle { ... };
(b) class DbiList : public List, public List { ... };
Expand All @@ -175,6 +306,7 @@ void f()
## 练习18.22

> 已知存在如下所示的类的继承体系,其中每个类都定义了一个默认构造函数:
```cpp
class A { ... };
class B : public A { ... };
Expand All @@ -191,7 +323,7 @@ MI mi;

## 练习18.23

> 使用练习18.22的继承体系以及下面定义的类 D,同时假定每个类都定义了默认构造函数,请问下面的哪些类型转换是不被允许的?
> 使用练习18.22的继承体系以及下面定义的类 `D`,同时假定每个类都定义了默认构造函数,请问下面的哪些类型转换是不被允许的?
```cpp
class D : public X, public C { ... };
p *pd = new D;
Expand All @@ -203,11 +335,11 @@ p *pd = new D;

## 练习18.24

> 在第714页,我们使用一个指向 Panda 对象的 Bear 指针进行了一系列调用,假设我们使用的是一个指向 Panda 对象的 ZooAnimal 指针将会发生什么情况,请对这些调用语句逐一进行说明。
> 在第714页,我们使用一个指向 `Panda` 对象的 `Bear` 指针进行了一系列调用,假设我们使用的是一个指向 `Panda` 对象的 `ZooAnimal` 指针将会发生什么情况,请对这些调用语句逐一进行说明。
## 练习18.25

> 假设我们有两个基类 Base1 和 Base2,它们各自定义了一个名为 print 的虚成员和一个虚析构函数。从这两个基类中文名派生出下面的类,它们都重新定义了 print 函数:
> 假设我们有两个基类 `Base1``Base2` ,它们各自定义了一个名为 `print` 的虚成员和一个虚析构函数。从这两个基类中文名派生出下面的类,它们都重新定义了 `print` 函数:
```cpp
class D1 : public Base1 { /* ... */};
class D2 : public Base2 { /* ... */};
Expand Down Expand Up @@ -260,15 +392,15 @@ protected:
## 练习18.26
> 已知如上所示的继承体系,下面对print的调用为什么是错误的?适当修改MI,令其对print的调用可以编译通过并正确执行
> 已知如上所示的继承体系,下面对`print`的调用为什么是错误的?适当修改`MI`,令其对`print`的调用可以编译通过并正确执行
```cpp
MI mi;
mi.print(42);
```

## 练习18.27

> 已知如上所示的继承体系,同时假定为MI添加了一个名为foo的函数
> 已知如上所示的继承体系,同时假定为MI添加了一个名为`foo`的函数
```cpp
int ival;
double dval;
Expand All @@ -286,7 +418,7 @@ void MI::foo(double cval)
## 练习18.28
> 已知存在如下的继承体系,在 VMI 类的内部哪些继承而来的成员无须前缀限定符就能直接访问?哪些必须有限定符才能访问?说明你的原因。
> 已知存在如下的继承体系,在 `VMI` 类的内部哪些继承而来的成员无须前缀限定符就能直接访问?哪些必须有限定符才能访问?说明你的原因。
```cpp
struct Base {
void bar(int);
Expand Down Expand Up @@ -330,4 +462,4 @@ Base *pb; Class *pc; MI *pmi; D2 *pd2;

## 练习18.30

> 在Base中定义一个默认构造函数、一个拷贝构造函数和一个接受int形参的构造函数。在每个派生类中分别定义这三种构造函数,每个构造函数应该使用它的形参初始化其Base部分
> `Base`中定义一个默认构造函数、一个拷贝构造函数和一个接受`int`形参的构造函数。在每个派生类中分别定义这三种构造函数,每个构造函数应该使用它的形参初始化其`Base`部分
Loading

0 comments on commit a475fa4

Please sign in to comment.