Skip to content

Commit 1ace8be

Browse files
committed
Updated to Chapter 12, Section 2; Rearranged images
1 parent 74f1c2c commit 1ace8be

File tree

155 files changed

+968
-323
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

155 files changed

+968
-323
lines changed

.vscode/Test.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
1-
#include <iostream>
2-
using namespace std;
3-
void g() { throw string("error"); }
4-
void f() {
5-
int *p = new int;
6-
try{
7-
g();
8-
} catch (const string &error) {
9-
delete p; //回收p指向的动态内存
10-
throw error; //把接收到的异常对象继续抛出
11-
}
12-
}
1+
#include<iostream>
2+
#include<exception>
3+
#include<stdexcept>
4+
#include<vector>
5+
void func()noexcept { }
6+
void func(int n) { }
137
int main() {
14-
try {
15-
f();
16-
} catch (const string &error) {
17-
cout << error;
18-
}
8+
std::vector<int> vec(3); //vec的长度为3
9+
std::cout << noexcept(vec.at(2))<<std::endl;
10+
std::cout << noexcept(vec.at(3))<<std::endl;
1911
return 0;
2012
}

.vscode/Test.exe

38.6 KB
Binary file not shown.

.vscode/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
"xtr1common": "cpp",
5353
"xutility": "cpp",
5454
"unordered_set": "cpp",
55-
"*.tpp": "cpp"
55+
"*.tpp": "cpp",
56+
"bitset": "cpp",
57+
"list": "cpp",
58+
"set": "cpp",
59+
"valarray": "cpp",
60+
"xhash": "cpp",
61+
"xtree": "cpp"
5662
}
5763
}

Structure.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,10 +817,12 @@
817817

818818
`array`类模板设计一个成员函数`at`,带范围检测,继承自`std::exception`
819819

820-
### `noexcept`限定
820+
#### `noexcept`限定符
821821

822822
简单介绍下`noexcept`限定符的使用。
823823

824+
### 实操:简单矩阵类的设计
825+
824826
## 输入、输出流简介
825827

826828
### 信息在流中的传递

code_in_book/12.2-12.3/Header.hpp

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#pragma once
2+
#include<iostream>
3+
#include<cstddef>
4+
#include<stdexcept>
5+
#include<algorithm>
6+
#include<initializer_list>
7+
#include<valarray>
8+
namespace user;
9+
template<typename T>
10+
class matrix{
11+
public:
12+
using value_type = T;
13+
using reference = T&;
14+
class index_error:public std::out_of_range{
15+
public:
16+
index_error(const char *msg="Index error"):out_of_range{msg}{}
17+
};
18+
class invalid_plus:public std::logic_error{
19+
public:
20+
invalid_plus(const char *msg="The number of rows or columns of the two matrices to be added is not equal"):logic_error{msg}{}
21+
};
22+
class invalid_multiplies:public std::logic_error{
23+
public:
24+
invalid_multiplies(const char *msg="The number of rows or columns of the two matrices to be multiplied is not equal"):logic_error{msg}{}
25+
};
26+
class invalid_concatenate:public std::logic_error{
27+
public:
28+
invalid_concatenate(const char *msg="Concatenate error"):logic_error{msg}{}
29+
};
30+
class cannot_compare:public std::logic_error{
31+
public:
32+
cannot_compare(const char *msg="The size of two matricies are not equal. Cannot compare"):logic_error{msg}{}
33+
};
34+
matrix(std::size_t, std::size_t);
35+
matrix(const std::initializer_list<std::initializer_list<value_type>>&);
36+
value_type operator()(std::size_t x,std::size_t y)const noexcept{return element_[x][y];}
37+
value_type operator()(std::size_t x,std::size_t y,bool value)noexcept{return element_[x][y]=value;}
38+
friend matrix operator+(const matrix&,const matrix&);
39+
friend matrix operator*(const matrix&,const matrix&);
40+
friend bool operator==(const matrix&,const matrix&);
41+
friend bool operator!=(const matrix&,const matrix&);
42+
friend bool operator<(const matrix&,const matrix&);
43+
inline iterator begin()noexcept{return element_.begin();}
44+
inline const_iterator begin()const noexcept{return element_.begin();}
45+
inline iterator end()noexcept{return element_.end();}
46+
inline const_iterator end()const noexcept{return element_.end();}
47+
inline reverse_iterator rbegin()noexcept{return element_.rbegin();}
48+
inline const_reverse_iterator rbegin()const noexcept{return element_.rbegin();}
49+
inline reverse_iterator rend()noexcept{return element_.rend();}
50+
inline const_reverse_iterator rend()const noexcept{return element_.rend();}
51+
inline std::pair<std::size_t,std::size_t> size()const noexcept{return std::make_pair(n_,m_);}
52+
matrix transpose()const noexcept;
53+
template<concatenate_direction direction>
54+
friend matrix concatenate(const matrix&,const matrix&);
55+
friend std::ostream& operator<<(std::ostream&,const matrix&);
56+
private:
57+
const std::size_t n_;
58+
const std::size_t m_;
59+
std::vector<std::vector<bool>> element_;
60+
};
61+
matrix::matrix(std::size_t n,std::size_t m)noexcept:n_{n},m_{m},element_{}{
62+
element_.resize(n_);
63+
for(auto &row:element_)
64+
row.resize(m_);
65+
}
66+
matrix::matrix(const std::initializer_list<std::initializer_list<bool>> &init):n_{init.size()},m_{init.begin()->size()},element_{}{
67+
element_.resize(n_);
68+
std::size_t i=0;
69+
for(auto &row:init){
70+
element_[i].resize(m_);
71+
if(row.size()!=m_)
72+
throw std::out_of_range{"All rows in the initializer list must have the same size."};
73+
std::copy(row.begin(),row.end(),element_[i++].begin());
74+
}
75+
}
76+
matrix operator+(const matrix &lhs,const matrix &rhs){
77+
if(lhs.n_!=rhs.n_||lhs.m_!=rhs.m_)
78+
throw matrix::invalid_plus{};
79+
matrix result(lhs.n_,lhs.m_);
80+
for(std::size_t i=0;i<lhs.n_;i++)
81+
for(std::size_t j=0;j<lhs.m_;j++)
82+
result(i,j,lhs(i,j)^rhs(i,j));
83+
return result;
84+
}
85+
matrix operator*(const matrix &lhs,const matrix &rhs){
86+
if(lhs.m_!=rhs.n_)
87+
throw matrix::invalid_multiplies{};
88+
matrix result(lhs.n_,rhs.m_);
89+
for(std::size_t i=0;i<lhs.n_;i++)
90+
for(std::size_t j=0;j<rhs.m_;j++)
91+
for(std::size_t k=0;k<lhs.m_;k++)
92+
result(i,j,result(i,j)^lhs(i,k)&rhs(k,j));
93+
return result;
94+
}
95+
bool operator==(const matrix &lhs,const matrix &rhs){
96+
if(lhs.m_!=rhs.m_||lhs.n_!=rhs.n_)
97+
throw matrix::cannot_compare{};
98+
for(std::size_t i=0;i<lhs.n_;i++)
99+
for(std::size_t j=0;j<lhs.m_;j++)
100+
if(lhs(i,j)!=rhs(i,j))
101+
return false;
102+
return true;
103+
}
104+
bool operator!=(const matrix &lhs,const matrix &rhs){
105+
if(lhs.m_!=rhs.m_||lhs.n_!=rhs.n_)
106+
throw matrix::cannot_compare{};
107+
for(std::size_t i=0;i<lhs.n_;i++)
108+
for(std::size_t j=0;j<lhs.m_;j++)
109+
if(lhs(i,j)!=rhs(i,j))
110+
return true;
111+
return false;
112+
}
113+
bool operator<(const matrix &lhs,const matrix &rhs){
114+
if(lhs.m_!=rhs.m_||lhs.n_!=rhs.n_)
115+
throw matrix::cannot_compare{};
116+
std::size_t l_weight{0},r_weight{0};
117+
for(std::size_t i=0;i<lhs.n_;i++)
118+
for(std::size_t j=0;j<lhs.m_;j++){
119+
if(lhs(i,j))
120+
l_weight++;
121+
if(rhs(i,j))
122+
r_weight++;
123+
}
124+
if(l_weight<r_weight)
125+
return true;
126+
else if(l_weight>r_weight)
127+
return false;
128+
for(std::size_t i=0;i<lhs.n_;i++)
129+
for(std::size_t j=0;j<lhs.m_;j++){
130+
if(lhs(i,j)<rhs(i,j))
131+
return true;
132+
else if(lhs(i,j)>rhs(i,j))
133+
return false;
134+
}
135+
return false;
136+
}
137+
matrix matrix::transpose()const noexcept{
138+
matrix result(m_,n_);
139+
for(std::size_t i=0;i<m_;i++)
140+
for(std::size_t j=0;j<n_;j++)
141+
result(i,j,element_[j][i]);
142+
return result;
143+
}
144+
template<concatenate_direction direction>
145+
matrix concatenate(const matrix&,const matrix&);
146+
template<>
147+
matrix concatenate<vertical>(const matrix &uhs,const matrix &dhs){
148+
if(uhs.m_!=dhs.m_)
149+
throw matrix::invalid_concatenate{"Two matrices to be concatenated have different number of columns"};
150+
matrix result(uhs.n_+dhs.n_,uhs.m_);
151+
for(std::size_t j=0;j<uhs.m_;j++){
152+
for(std::size_t i=0;i<uhs.n_;i++)
153+
result(i,j,uhs(i,j));
154+
for(std::size_t i=0;i<dhs.n_;i++)
155+
result(uhs.n_+i,j,dhs(i,j));
156+
}
157+
return result;
158+
}
159+
template<>
160+
matrix concatenate<horizontal>(const matrix &lhs,const matrix &rhs){
161+
if(lhs.n_!=rhs.n_)
162+
throw matrix::invalid_concatenate{"Two matrices to be concatenated have different number of rows."};
163+
matrix result(lhs.n_,lhs.m_+rhs.m_);
164+
for(std::size_t i=0;i<lhs.n_;i++){
165+
for(std::size_t j=0;j<lhs.m_;j++)
166+
result(i,j,lhs(i,j));
167+
for(std::size_t j=0;j<rhs.m_;j++)
168+
result(i,lhs.m_+j,rhs(i,j));
169+
}
170+
return result;
171+
}
172+
inline matrix transpose(const matrix &mat){
173+
return mat.transpose();
174+
}
175+
matrix Identity(std::size_t size){
176+
matrix result(size,size);
177+
for(std::size_t i=0;i<size;i++)
178+
result(i,i,true);
179+
return result;
180+
}
181+
matrix ItoB(unsigned x,std::size_t len){
182+
matrix result(1,len);
183+
for(std::size_t i=0;i<len;i++)
184+
result(0,len-1-i,1<<i&x);
185+
return result;
186+
}
187+
inline std::ostream& operator<<(std::ostream &out,const output_method &style){
188+
outstyle=style;
189+
return out;
190+
}
191+
std::ostream& operator<<(std::ostream &out,const matrix &mat){
192+
for(auto row:mat){
193+
for(auto x:row){
194+
out<<x;
195+
if(outstyle==as_matrix)
196+
out<<' ';
197+
}
198+
}
199+
return out;
200+
}
201+
//~code
202+
};

generalized_parts/01_welcome_to_cpp/01_start_with_a_cpp_program.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ \section{开始一个C++程序}
1010
\end{enumerate}
1111
\begin{figure}[htbp]
1212
\centering
13-
\includegraphics[width=0.8\textwidth]{../images/generalized_parts/01_From_source_code_to_executable.png}
13+
\includegraphics[width=0.8\textwidth]{../images/generalized_parts/01_From_source_code_to_executable.drawio.png}
1414
\caption{从源代码到可执行文件}
1515
\end{figure}
1616
实际上的过程会更复杂,比如在编译之前还会进行预处理(Preprocess)。但是我们现在还不需要操心这么多,因为在按下``编译''键之后,预处理和编译都会进行,所以不妨把它统称为一个过程。\par

generalized_parts/01_welcome_to_cpp/05_sizeof_and_memory.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ \subsection*{内存如何存储数据?}
1515
回到我们刚才的比喻。存储器的内部结构是排列有序的房屋。每个房屋代表一个字节,它是相对独立的最小可寻址单元。而每个房屋有8个房间,各自存储一比特的信息。图1.3可以帮助我们更直观地理解这种关系。\par
1616
\begin{figure}[htbp]
1717
\centering
18-
\includegraphics[width=0.75\textwidth]{../images/generalized_parts/01_Memory_byte_and_bit.png}
18+
\includegraphics[width=0.75\textwidth]{../images/generalized_parts/01_Memory_byte_and_bit.drawio.png}
1919
\caption{存储器、字节与比特}
2020
\end{figure}
2121
\subsection*{信息与容量}

generalized_parts/02_basic_operation_on_data/03_operators.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ \subsection*{运算符的优先级}
6565
C++中的赋值运算符优先级很低,比四则运算都要低。那么按照我们的思路,如果加法,乘法和赋值运算符同时出现,我们应该先给乘法套括号,然后是加法,最后才是赋值。如图2.1所示。\par
6666
\begin{figure}[htbp]
6767
\centering
68-
\includegraphics[width=0.5\textwidth]{../images/generalized_parts/02_Precedence_of_multiply_addition_and_assignment.png}
68+
\includegraphics[width=0.5\textwidth]{../images/generalized_parts/02_Precedence_of_multiply_addition_and_assignment.drawio.png}
6969
\caption{代码 \lstinline@num=a*b+c*d;@ 的套括号解释}
7070
\end{figure}
7171
再看这段代码:
@@ -103,7 +103,7 @@ \subsection*{运算符的结合性}
103103
除法运算符所在的优先级,其结合性是从左向右的,所以在乘法、除法和取模混合运算时,它就会从左向右套括号,而直观表现上就是``从左向右算''。赋值运算符所在的优先级,其结合性是从右向左的,所以在连续赋值的时候,它就会从右向左套括号,而直观表现上就是``从右向左算''\par
104104
\begin{figure}[htbp]
105105
\centering
106-
\includegraphics[width=0.4\textwidth]{../images/generalized_parts/02_Associativity_of_division_and_assignment.png}
106+
\includegraphics[width=0.4\textwidth]{../images/generalized_parts/02_Associativity_of_division_and_assignment.drawio.png}
107107
\caption{除法运算符和赋值运算符的结合性}
108108
\end{figure}
109109
所以连续除法中 \lstinline@8/4/2@ 就应该解释成 \lstinline@(8/4)/2@ 而非 \lstinline@8/(4/2)@;而连续赋值中 \lstinline@a=b=0@ 就应该解释成 \lstinline@a=(b=0)@ 而非 \lstinline@(a=b)=0@。如图2.2所示。\par

generalized_parts/02_basic_operation_on_data/04_type_cast.tex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ \subsection*{隐式类型转换}
3030
接下来是这个 \lstinline@double@ 型的 \lstinline@1.*a@ 作为整体与 \lstinline@int@ 型的 \lstinline@b@ 相除,于是 \lstinline@int@ 型的 \lstinline@b@ 也需要被转换成 \lstinline@double@ 型数据再参与运算。而 \lstinline@double@ 型数据的除法就不致于有截尾级别的精度损失了。整个过程如图2.3(a)所示。\par
3131
\begin{figure}[htbp]
3232
\centering
33-
\includegraphics[width=0.95\textwidth]{../images/generalized_parts/02_Implicit_type_cast_from_int_to_double.png}
33+
\includegraphics[width=0.95\textwidth]{../images/generalized_parts/02_Implicit_type_cast_from_int_to_double.drawio.png}
3434
\caption{\lstinline@1.*a/b@ 与 \lstinline@a/b*1.@ 的隐式类型转换过程图解}
3535
\end{figure}
3636
那么我写成这样行不行呢?
@@ -52,7 +52,7 @@ \subsection*{隐式类型转换}
5252
\textbf{布尔转换(Boolean Conversions)}是隐式类型转换当中比较特殊,而又十分常用的一类转换。如图2.4所示,它的转换规则很简单:如果别的基本数据类型要转换为 \lstinline@bool@ 类型的话,\lstinline@0@ 会转换成 \lstinline@false@,而其它的所有数都会被转换成 \lstinline@true@;如果 \lstinline@bool@ 类型要转换成其它的基本数据类型的话,\lstinline@false@ 会转换成 \lstinline@0@,而 \lstinline@true@ 会转换成 \lstinline@1@。\par
5353
\begin{figure}[htbp]
5454
\centering
55-
\includegraphics[width=0.7\textwidth]{../images/generalized_parts/02_boolean_conversion.png}
55+
\includegraphics[width=0.7\textwidth]{../images/generalized_parts/02_boolean_conversion.drawio.png}
5656
\caption{布尔转换规则}
5757
\end{figure}
5858
\subsection*{显式类型转换}
@@ -97,7 +97,7 @@ \subsection*{显式类型转换}
9797
在这里,乘法运算符在面临一个 \lstinline@int@ 操作数和 \lstinline@double@ 操作数的时候,它会怎么做呢?如图2.5所示,它将把 \lstinline@int@ 通过隐式类型转换变为 \lstinline@double@ 型!这样一来我们就白干了。\par
9898
\begin{figure}[htbp]
9999
\centering
100-
\includegraphics[width=0.6\textwidth]{../images/generalized_parts/02_Explicit_type_cast_from_double_to_int_in_vain.png}
100+
\includegraphics[width=0.6\textwidth]{../images/generalized_parts/02_Explicit_type_cast_from_double_to_int_in_vain.drawio.png}
101101
\caption{显式类型转换,但是又被隐式类型转换改回去了}
102102
\end{figure}
103103
总而言之,类型转换是一个非常复杂的话题。限于我们目前接触到的类型尚少,这里只作简单概括。将来我们接触复合类型和自定义类型的时候,还会对此作针对性讲解的。\par

generalized_parts/03_control_flow/01_introduction_to_structure_process_and_order.tex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ \subsubsection*{输入}
6464
想像一下我们使用命令行界面时的情形:如图3.3所示,有一个\textbf{光标(Cursor)}在界面上不停闪烁,等待我们输入。当我们按下一个按键,比如 \lstinline@d@,光标的位置上就会出现一个 \lstinline@d@,同时光标后移一位。如果我们按下退格键,光标就会前移一位,并删除上一个输入字符。如果用方向键前移光标的位置并再次输入内容,还可能把之前的输入覆盖掉\footnote{只在覆盖模式下有效。计算机文字处理器都有输入两种模式:插入模式和覆盖模式。对于有些系统来说,命令行界面默认使用的是插入模式。}。\par
6565
\begin{figure}[htbp]
6666
\centering
67-
\includegraphics[width=\textwidth]{../images/generalized_parts/03_input_to_cmd.png}
67+
\includegraphics[width=\textwidth]{../images/generalized_parts/03_input_to_cmd.drawio.png}
6868
\caption{命令行界面输入场景示例}
6969
\end{figure}
7070
值得注意的是回车键。在我们按下回车键之前,我们输入的内容并未实际发送给计算机,我们可以修改这些内容;而一旦按下了回车键,本行的输入内容将会发送给程序\footnote{这才是真正意义上完成了一次输入。},我们也没机会再修改了。\par
@@ -84,7 +84,7 @@ \subsection*{程序的结构}
8484
图3.4是对结构化程序理论的直观解释。\par
8585
\begin{figure}[htbp]
8686
\centering
87-
\includegraphics[width=0.6\textwidth]{../images/generalized_parts/03_structured_program_theorem.png}
87+
\includegraphics[width=0.6\textwidth]{../images/generalized_parts/03_structured_program_theorem.drawio.png}
8888
\caption{顺序、选择和循环结构}
8989
\end{figure}
9090
对于顺序结构,我们已经很熟悉。我们之前已经尝试了好几个程序的代码。在这些程序的主函数中,代码的顺序就对应着程序执行的顺序。所以一个变量要先定义,后使用。
@@ -152,7 +152,7 @@ \subsubsection*{逻辑运算符}
152152
在C++标准中,有三个逻辑运算符:逻辑非(\lstinline@!@)、逻辑与(\lstinline@&&@)和逻辑或(\lstinline@||@)。它们在选择和循环结构中很常用,所以在这里不得不提。我们在前面已经分析了很多运算符,这里只要按照相同的思路来分析就可以了。先来分析逻辑与运算符。\par
153153
\begin{figure}[htbp]
154154
\centering
155-
\includegraphics[width=0.8\textwidth]{../images/generalized_parts/03_truth_table_of_logic_operators.png}
155+
\includegraphics[width=0.8\textwidth]{../images/generalized_parts/03_truth_table_of_logic_operators.drawio.png}
156156
\caption{逻辑与、逻辑或、逻辑非运算符的真值表}
157157
\end{figure}
158158
逻辑与运算符只能接收 \lstinline@bool@ 类型的操作数;非 \lstinline@bool@ 型的操作数都会通过\hyperref[con:boolean_conversions]{布尔转换}来变成 \lstinline@bool@ 型。\par

0 commit comments

Comments
 (0)