Skip to content

Commit

Permalink
Style: 在列表项之间添加空行
Browse files Browse the repository at this point in the history
  • Loading branch information
czs108 committed Apr 6, 2022
1 parent a43a5ef commit 78ea77d
Show file tree
Hide file tree
Showing 18 changed files with 253 additions and 40 deletions.
18 changes: 15 additions & 3 deletions Chapter-10 Generic Algorithms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,11 @@ for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
除了为每种容器定义的迭代器之外,标准库还在头文件`iterator`中定义了另外几种迭代器。

- 插入迭代器(insert iterator):该类型迭代器被绑定到容器对象上,可用来向容器中插入元素。

- 流迭代器(stream iterator):该类型迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流。

- 反向迭代器(reverse iterator):该类型迭代器向后而不是向前移动。除了`forward_list`之外的标准库容器都有反向迭代器。

- 移动迭代器(move iterator):该类型迭代器用来移动容器元素。

### 插入迭代器(Insert Iterators)
Expand All @@ -298,7 +301,9 @@ for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
插入器有三种类型,区别在于元素插入的位置:

- `back_inserter`:创建一个调用`push_back`操作的迭代器。

- `front_inserter`:创建一个调用`push_front`操作的迭代器。

- `inserter`:创建一个调用`insert`操作的迭代器。此函数接受第二个参数,该参数必须是一个指向给定容器的迭代器,元素会被插入到该参数指向的元素之前。

```c++
Expand Down Expand Up @@ -407,14 +412,18 @@ C++标准指定了泛型和数值算法的每个迭代器参数的最小类别

- 输入迭代器(input iterator):可以读取序列中的元素,只能用于单遍扫描算法。必须支持以下操作:

- - 用于比较两个迭代器相等性的相等`==`和不等运算符`!=`。
- 用于比较两个迭代器相等性的相等`==`和不等运算符`!=`。

- 用于推进迭代器位置的前置和后置递增运算符`++`。

- 用于读取元素的解引用运算符`*`;解引用只能出现在赋值运算符右侧。

- 用于读取元素的箭头运算符`->`。

- 输出迭代器(output iterator):可以读写序列中的元素,只能用于单遍扫描算法,通常指向目的位置。必须支持以下操作:

- - 用于推进迭代器位置的前置和后置递增运算符`++`。
- 用于推进迭代器位置的前置和后置递增运算符`++`。

- 用于读取元素的解引用运算符`*`;解引用只能出现在赋值运算符左侧(向已经解引用的输出迭代器赋值,等价于将值写入其指向的元素)。

- 前向迭代器(forward iterator):可以读写序列中的元素。只能在序列中沿一个方向移动。支持所有输入和输出迭代器的操作,而且可以多次读写同一个元素。因此可以使用前向迭代器对序列进行多遍扫描。
Expand All @@ -423,9 +432,12 @@ C++标准指定了泛型和数值算法的每个迭代器参数的最小类别

- 随机访问迭代器(random-access iterator):可以在常量时间内访问序列中的任何元素。除了支持所有双向迭代器的操作之外,还必须支持以下操作:

- - 用于比较两个迭代器相对位置的关系运算符`<`、`<=`、`>`、`>=`。
- 用于比较两个迭代器相对位置的关系运算符`<`、`<=`、`>`、`>=`。

- 迭代器和一个整数值的加减法运算`+`、`+=`、`-`、`-=`,计算结果是迭代器在序列中前进或后退给定整数个元素后的位置。

- 用于两个迭代器上的减法运算符`-`,计算得到两个迭代器的距离。

- 下标运算符`[]`。

### 算法形参模式(Algorithm Parameter Patterns)
Expand Down
4 changes: 4 additions & 0 deletions Chapter-11 Associative Containers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
关联容器支持高效的关键字查找和访问操作。2个主要的关联容器(associative-container)类型是`map`和`set`。

- `map`中的元素是一些键值对(key-value):关键字起索引作用,值表示与索引相关联的数据。

- `set`中每个元素只包含一个关键字,支持高效的关键字查询操作:检查一个给定关键字是否在`set`中。

标准库提供了8个关联容器,它们之间的不同体现在三个方面:

- 是`map`还是`set`类型。

- 是否允许保存重复的关键字。

- 是否按顺序保存元素。

允许重复保存关键字的容器名字都包含单词`multi`;无序保存元素的容器名字都以单词`unordered`开头。
Expand Down Expand Up @@ -175,6 +178,7 @@ word_count.insert(map<string, size_t>::value_type(word, 1));
`insert`或`emplace`的返回值依赖于容器类型和参数:

- 对于不包含重复关键字的容器,添加单一元素的`insert`和`emplace`版本返回一个`pair`,表示操作是否成功。`pair`的`first`成员是一个迭代器,指向具有给定关键字的元素;`second`成员是一个`bool`值。如果关键字已在容器中,则`insert`直接返回,`bool`值为`false`。如果关键字不存在,元素会被添加至容器中,`bool`值为`true`。

- 对于允许包含重复关键字的容器,添加单一元素的`insert`和`emplace`版本返回指向新元素的迭代器。

### 删除元素(Erasing Elements)
Expand Down
6 changes: 6 additions & 0 deletions Chapter-12 Dynamic Memory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ r = q; // assign to r, making it point to a different address
程序使用动态内存通常出于以下三种原因之一:

- 不确定需要使用多少对象。

- 不确定所需对象的准确类型。

- 需要在多个对象间共享数据。

### 直接管理内存(Managing Memory Directly)
Expand Down Expand Up @@ -209,9 +211,13 @@ void f(destination &d /* other parameters */)
智能指针规范:

- 不使用相同的内置指针值初始化或`reset`多个智能指针。

- 不释放`get`返回的指针。

- 不使用`get`初始化或`reset`另一个智能指针。

- 使用`get`返回的指针时,如果最后一个对应的智能指针被销毁,指针就无效了。

- 使用`shared_ptr`管理并非`new`分配的资源时,应该传递删除函数。

### unique_ptr(unique_ptr)
Expand Down
8 changes: 8 additions & 0 deletions Chapter-13 Copy Control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
一个类通过定义五种特殊的成员函数来控制对象的拷贝、移动、赋值和销毁操作。

- 拷贝构造函数(copy constructor)

- 拷贝赋值运算符(copy-assignment operator

- 移动构造函数(move constructor)

- 移动赋值运算符(move-assignment operator

- 析构函数(destructor)

这些操作统称为拷贝控制操作(copy control)。
Expand Down Expand Up @@ -68,8 +72,11 @@ string nines = string(100, '9'); // copy initialization
发生拷贝初始化的情况:

- 用`=`定义变量。

- 将对象作为实参传递给非引用类型的形参。

- 从返回类型为非引用类型的函数返回对象。

- 用花括号列表初始化数组中的元素或聚合类中的成员。

当传递一个实参或者从函数返回一个值时,不能隐式使用`explicit`构造函数。
Expand Down Expand Up @@ -187,6 +194,7 @@ struct NoCopy
`=delete`和`=default`有两点不同:

- `=delete`可以对任何函数使用;`=default`只能对具有合成版本的函数使用。

- `=delete`必须出现在函数第一次声明的地方;`=default`既能出现在类内,也能出现在类外。

析构函数不能是删除的函数。对于析构函数被删除的类型,不能定义该类型的变量或者释放指向该类型动态分配对象的指针。
Expand Down
29 changes: 20 additions & 9 deletions Chapter-14 Overloaded Operations and Conversions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ string u = "hi" + s; // would be an error if + were a member of string
如何选择将运算符定义为成员函数还是普通函数:

- 赋值`=`、下标`[]`、调用`()`和成员访问箭头`->`运算符必须是成员函数。

- 复合赋值运算符一般是成员函数,但并非必须。

- 改变对象状态或者与给定类型密切相关的运算符,如递增、递减、解引用运算符,通常是成员函数。

- 具有对称性的运算符可能转换任意一端的运算对象,如算术、相等性、关系和位运算符,通常是普通函数。

## 输入和输出运算符(Input and Output Operators)
Expand Down Expand Up @@ -88,7 +91,9 @@ istream &operator>>(istream &is, Sales_data &item)
以下情况可能导致读取操作失败:

- 读取了错误类型的数据。

- 读取操作到达文件末尾。

- 遇到输入流的其他错误。

当读取操作发生错误时,输入操作符应该负责从错误状态中恢复。
Expand Down Expand Up @@ -132,7 +137,7 @@ Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}

bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs);
Expand All @@ -146,7 +151,9 @@ Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
关系运算符设计准则:

- 定义顺序关系,令其与关联容器中对关键字的要求保持一致。

- 如果类定义了`operator==`,则关系运算符的定义应该与`operator==`保持一致。特别是,如果两个对象是不相等的,那么其中一个对象应该小于另一个对象。

- 只有存在唯一一种逻辑可靠的小于关系时,才应该考虑为类定义`operator<`。

## 赋值运算符(Assignment Operators)
Expand Down Expand Up @@ -267,6 +274,7 @@ public:
对于形如`point->mem`的表达式来说,`point`必须是指向类对象的指针或者是一个重载了`operator->`的类的对象。`point`类型不同,`point->mem`的含义也不同。

- 如果`point`是指针,则调用内置箭头运算符,表达式等价于`(*point).mem`。

- 如果`point`是重载了`operator->`的类的对象,则使用`point.operator->()`的结果来获取`mem`,表达式等价于`(point.operator->())->mem`。其中,如果该结果是一个指针,则执行内置操作,否则重复调用当前操作。

## 函数调用运算符(Function-Call Operator)
Expand Down Expand Up @@ -388,7 +396,7 @@ struct div
function<int(int, int)> f1 = add; // function pointer
function<int(int, int)> f2 = div(); // object of a function-object class
function<int(int, int)> f3 = [](int i, int j) { return i * j; }; // lambda

cout << f1(4,2) << endl; // prints 6
cout << f2(4,2) << endl; // prints 2
cout << f3(4,2) << endl; // prints 8
Expand Down Expand Up @@ -420,9 +428,9 @@ public:
{
if (i < 0 || i > 255)
throw std::out_of_range("Bad SmallInt value");
}
}
operator int() const { return val; }

private:
std::size_t val;
};
Expand Down Expand Up @@ -458,8 +466,11 @@ static_cast<int>(si) + 3; // ok: explicitly request the conversion
如果表达式被用作条件,则编译器会隐式地执行显式类型转换。

- `if`、`while`、`do-while`语句的条件部分。

- `for`语句头的条件表达式。

- 条件运算符`? :`的条件表达式。

- 逻辑非运算符`!`、逻辑或运算符`||`、逻辑与运算符`&&`的运算对象。

类类型向`bool`的类型转换通常用在条件部分,因此`operator bool`一般被定义为显式的。
Expand All @@ -479,13 +490,13 @@ static_cast<int>(si) + 3; // ok: explicitly request the conversion
A(const B&); // converts a B to an A
// other members
};

struct B
{
operator A() const; // also converts a B to an A
// other members
};

A f(const A&);
B b;
A a = f(b); // error ambiguous: f(B::operator A())
Expand All @@ -503,7 +514,7 @@ static_cast<int>(si) + 3; // ok: explicitly request the conversion
operator double() const; // conversions to arithmetic types
// other members
};

void f2(long double);
A a;
f2(a); // error ambiguous: f(A::operator int())
Expand Down Expand Up @@ -554,11 +565,11 @@ manip2(10); // manip2(C(10) or manip2(E(double(10)))
class SmallInt
{
friend SmallInt operator+(const SmallInt&, const SmallInt&);

public:
SmallInt(int = 0); // conversion from int
operator int() const { return val; } // conversion to int

private:
std::size_t val;
};
Expand Down
14 changes: 10 additions & 4 deletions Chapter-15 Object-Oriented Programming/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Quote &r = bulk; // r bound to the Quote part of bulk
每个类控制它自己的成员初始化过程,派生类必须使用基类的构造函数来初始化它的基类部分。派生类的构造函数通过构造函数初始化列表来将实参传递给基类构造函数。

```c++
Bulk_quote(const std::string& book, double p,
Bulk_quote(const std::string& book, double p,
std::size_t qty, double disc) :
Quote(book, p), min_qty(qty), discount(disc) { }
```
Expand Down Expand Up @@ -150,7 +150,7 @@ struct B
void f3();
};

struct D1 : B
struct D1 : B
{
void f1(int) const override; // ok: f1 matches f1 in the base
void f2(int) override; // error: B has no f2(int) function
Expand Down Expand Up @@ -237,13 +237,17 @@ void clobber(Base &b) { b.prot_mem = 0; }
派生访问说明符的作用是控制派生类(包括派生类的派生类)用户对于基类成员的访问权限。

- 如果使用公有继承,则基类的公有成员和受保护成员在派生类中属性不发生改变。

- 如果使用受保护继承,则基类的公有成员和受保护成员在派生类中变为受保护成员。

- 如果使用私有继承,则基类的公有成员和受保护成员在派生类中变为私有成员。

派生类到基类转换的可访问性(假定`D`继承自`B`):

- 只有当`D`公有地继承`B`时,用户代码才能使用派生类到基类的转换。

- 不论`D`以什么方式继承`B`,`D`的成员函数和友元都能使用派生类到基类的转换。

- 如果`D`继承`B`的方式是公有的或者受保护的,则`D`的派生类的成员函数和友元可以使用`D`到`B`的类型转换;反之,如果`D`继承`B`的方式是私有的,则不能使用。

对于代码中的某个给定节点来说,如果基类的公有成员是可访问的,则派生类到基类的类型转换也是可访问的。
Expand Down Expand Up @@ -313,7 +317,7 @@ protected:

struct Derived : Base
{
int get_mem() { return mem; } // returns Derived::mem
int get_mem() { return mem; } // returns Derived::mem
protected:
int mem; // hides mem in the base
};
Expand Down Expand Up @@ -342,7 +346,7 @@ class Base
{
private:
int x;

public:
virtual void mf1() = 0;
virtual void mf1(int);
Expand Down Expand Up @@ -403,7 +407,9 @@ delete itemP; // destructor for Bulk_quote called
派生类中删除的拷贝控制与基类的关系:

- 如果基类中的默认构造函数、拷贝构造函数、拷贝赋值运算符或析构函数是被删除的或者不可访问的函数,则派生类中对应的成员也会是被删除的。因为编译器不能使用基类成员来执行派生类对象中基类部分的构造、赋值或销毁操作。

- 如果基类的析构函数是被删除的或者不可访问的,则派生类中合成的默认和拷贝构造函数也会是被删除的。因为编译器无法销毁派生类对象中的基类部分。

- 编译器不会合成一个被删除的移动操作。当我们使用`=default`请求一个移动操作时,如果基类中对应的操作是被删除的或者不可访问的,则派生类中的操作也会是被删除的。因为派生类对象中的基类部分不能移动。同样,如果基类的析构函数是被删除的或者不可访问的,则派生类的移动构造函数也会是被删除的。

在实际编程中,如果基类没有默认、拷贝或移动构造函数,则一般情况下派生类也不会定义相应的操作。
Expand Down
Loading

0 comments on commit 78ea77d

Please sign in to comment.