目录
85. How to Do Binary Input/Output
91. C++11: Left Value, Pure Right Value and eXpiring Value
92. Overloading General Binary Arithmetic Operators
93. Overloading Shorthand Binary Arithmetic Operators
95. Overloading the Unary Operator
96. Overloading the - Operators
97. Overloading the ++ and -- Operators
98. Overloading << / >> Operator
99. Overloading Object Converting Operator
100. Overloading the = Operator
101. More on Operator Overloading
103. Overview of Exception-Handling
104. Exception-Handling Advantages
105. Exception Match and Exception Classes
106. Build-in Exception Classes
114. When Do We Use Exceptions?
115. Meta-Programming and Generic Programming
118. Function Template Instantiation
81. Formating Output
格式化输出
-
setw manipulator(“设置域宽”控制符)
要包含头文件 <iomanip>
1.1. setw(n) 设置域宽,即数据所占的总字符数
std::cout << std::setw(3) << 'a' << std::endl;
输出:
_ _a
1.2. setw()控制符只对其后输出的第一个数据有效,其他控制符则对其后的所有输入输出产生影响。
std::cout << std::setw(5) << 'a' << 'b' << std::endl;
输出:
_ _ _ _ab
1.3. setw()的默认为setw(0),按实际输出
1.4. 如果输出的数值占用的宽度超过setw(int n)设置的宽度,则按实际宽度输出。
float f=0.12345; std::cout << std::setw(3) << f << std::endl;
输出:
0.12345
-
setprecision manipulator(“设置浮点精度”控制符)
2.1. setprecision(int n)
(1) 控制显示浮点数的有效位
(2) n代表数字总位数
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
float f = 17 / 7.0;
cout << f << endl;
cout << setprecision(0) << f << endl;
cout << setprecision(1) << f << endl;
cout << setprecision(2) << f << endl;
cout << setprecision(3) << f << endl;
cout << setprecision(6) << f << endl;
cout << setprecision(8) << f << endl;
return 0;
}
Visual Studio输出:
2.42857
2.42857
2
2.4
2.43
2.42857
2.4285715
Eclipse CDT + GCC 8.2输出:
2.42857
2
2
2.4
2.43
2.42857
2.4285715
-
setfill manipulator(“设置填充字符”控制符)
3.1. setfill(c)
设置填充字符,即“<<"符号后面的数据长度小于域宽时,使用什么字符进行填充。
std::cout << std::setfill('*') << std::setw(5) << 'a' << std::endl;
输出:
****a
-
Formatting Output in File Operation(在文件操作中格式化输入/输出)
The stream manipulator also works to format output to a file(流控制符同样可以用于文件输入/输出)
控制符 | 用途 |
---|---|
setw(width) | 设置输出字段的宽度(仅对其后第一个输出有效) |
setprecision(n) | 设置浮点数的输/入出精度(总有效数字个数等于n) |
fixed | 将浮点数以定点数形式输入/出(小数点后有效数字个数等于setprecision指定的n) |
showpoint | 将浮点数以带小数点和结尾0的形式输入/出,即便该浮点数没有小数部分 |
left | 输出内容左对齐 |
right | 输出内容右对齐 |
hexfloat/defaultfloat | C++11新增;前者以定点科学记数法的形式输出十六进制浮点数,后者还原默认浮点格式 |
get_money(money)put_money(money) | C++11新增;从流中读取货币值,或者将货币值输出到流。支持不同语言和地区的货币格式https://en.cppreference.com/w/cpp/io/manip/get_moneyhttps://en.cppreference.com/w/cpp/io/manip/put_money |
get_time(tm, format)put_time(tm,format) | C++11新增;从流中读取日期时间值,或者将日期时间值输出到流。https://en.cppreference.com/w/cpp/io/manip/get_timehttps://en.cppreference.com/w/cpp/io/manip/put_time |
82. Functions for I/O Stream
用于输入/输出流的函数
-
getline()
1.1. When using (>>), data are delimited by whitespace. (>>运算符用空格分隔数据)
对于文件内容:
Li Lei#Han Meimei#Adam
如下代码只能读入“Li”
ifstream input("name.txt");
std::string name;
input >> name;
1.2. Read in "Li Lei" with member function getline(char* buf, int size, char delimiter)
constexpr int SIZE{ 40 };
std::array<char , SIZE> name{};
while (!input.eof()) {// not end of file
input.getline(&name[ 0 ] , SIZE , '#');
std::cout << &name[ 0 ] << std::endl;
}
1.3. Read in "Li Lei" with non-member function std::getline(istream& is, string& str, char delimiter)
std::string name2{};
while (!input.eof()) {
std::getline(input, name2, '#');
std::cout << n << std::endl;
}
-
get() and put()
Two other useful functions are get and put.
2.1. get: read a character
int istream::get();
istream& get (char& c);
2.2. put write a character.
ostream& put (char c);
-
flush()
3.1. Flush output stream buffer (将输出流缓存中的数据写入目标文件)
ostream& flush();
3.2. 用法
cout.flush(); // 其它输出流对象也可以调用 flush()
cout << "Hello" << std::flush; // 与endl类似作为manipulator的调用方式
83. File Open Mode
文件的打开模式
-
fstream and File Open Modes (fstream与文件打开模式)
ofstream : 写数据; ifstream : 读数据
fstream = ofstream + ifstream
When opening an fstream object, a "file open mode" should be specified(创建fstream对象时,应指定文件打开模式)。
Mode(**模式****)** | Description(**描述****)** |
---|---|
ios::in | 打开文件读数据 |
ios::out | 打开文件写数据 |
ios::app | 把输出追加到文件末尾。app = append |
ios::ate | 打开文件,把文件光标移到末尾。ate = at end |
ios::trunc | 若文件存在则舍弃其内容。这是ios::out的默认行为。trunc = truncate |
ios::binary | 打开文件以二进制模式读写 |
-
Combining Modes (模式组合)
2.1. Open Mode的定义
// std::ios_base::openmode 被ios继承
typedef /implementation defined/ openmode;
static constexpr openmode app = /implementation defined/
2.2. Combine several modes (几种模式可以组合在一起)
using the | operator (bitwise inclusive OR) (用“位或”运算符)
2.3. To open a file "name.txt" for appending data (打开文件name.txt追加数据)
stream.open("name.txt", ios::out | ios::app);
84. Introduction to Binary IO
二进制输入输出简介
-
Text File vs Binary File (文本文件与二进制文件)
1.1. TEXT file vs BINARY file (not technically precise) (文本文件与二进制文件)
(1) Both stores as a sequence of bits (in binary format) (都按二进制格式存储比特序列)
(2) text file : interpreted as a sequence of characters (解释为一系列字符)
(3) binary file : interpreted as a sequence of bits. (解释为一系列比特)
1.2. For example, the decimal integer 199 (对于十进制整数199)
(1) 在文本文件中存为3个字符: '1', '9', '9';三个字符的ASCII码占3个字节:0x31, 0x39, 0x39
(2) 在二进制文件中存为字节类型的值:C7;十进制 199 = 十六进制 C7
-
Text I/O vs Binary I/O (文本读写与二进制读写)
2.1. 文本读写:Windows文件的换行(CRLF) vs *nix文件的换行(LF)
在Windows上,'\n'输出到文件中会自动编码为'\r' '\n' 两个字符
在*nix上,'\n' 字符输出到文件中不变
2.2. Text I/O is built upon binary I/O to provide a level of abstraction for character encoding and decoding. (文本模式的读写是建立在二进制模式读写的基础上的,只不过是将二进制信息进行了字符编解码)
-
File Open Mode: ios::binary
3.1. Binary I/O does not require conversions. (二进制读写无需信息转换)
numeric value è write (bin I/O) è file
value in memory è copy (no conversion) è file
3.2. How to perform binary I/O ? (如何进行二进制读写)
By default, a file is opened in text mode.(文件默认以文本模式打开)
open a file using the binary mode ios::binary.(用ios::binary以二进制模式打开文件)
Text I/O (**文本模式****)** | Binary I/O function:(**二进制模式****)** | |
---|---|---|
读 | operator >>; get(); getline(); | read(); |
写 | operator <<; put(); | write(); |
85. How to Do Binary Input/Output
如何实现二进制读写
-
The write Function (write函数)
1.1. prototype (函数原型)
ostream& write( const char* s, std::streamsize count )
1.2. 可直接将字符串写入文件
fstream fs("GreatWall.dat", ios::binary|ios::trunc);
char s[] = "ShanHaiGuan\nJuYongGuan";
fs.write(s, sizeof(s));
1.3. 如何将非字符数据写入文件
(1) Convert any data into a sequence of bytes (byte stream) (先将数据转换为字节序列,即字节流)
(2) Write the sequence of bytes to file with write() (再用write函数将字节序列写入文件)
-
How to convert any data into byte stream? (如何将信息转换为字节流)
2.1. reinterpret_cast
该运算符有两种用途:
(1) cast the address of a type to another type (将一种类型的地址转为另一种类型的地址)
(2) cast the address to a number, i.e. integer (将地址转换为数值,比如转换为整数)
2.2. 语法: reinterpret_cast<dataType>(address)
address is the starting address of the data (address是待转换的数据的起始地址)
dataType is the data type you are converting to. (dataType是要转至的目标类型)
For binary I/O, dataType is char . (对于二进制I/O来说,dataType是 char)
2.3. 例子
long int x {0};
int a[3] {21,42,63};
std::string str{"Hello"};
char* p1 = reinterpret_cast<char*>(&x); // variable address
char* p2 = reinterpret_cast<char*>(a); // array address
char* p3 = reinterpret_cast<char*>(&str); // object address
-
The read Function (read成员函数)
3.1. prototype (函数原型)
istream& read ( char* s, std::streamsize count );
3.2. 例子
// 读字符串
fstream bio("GreatWall.dat", ios::in | ios::binary);
char s[10];
bio.read(s, 5);
s[5] = '\0';
cout << s;
bio.close();
// 读其它类型数据(整数),需要使用 reinterpret_cast
fstream bio("temp.dat", ios::in | ios::binary);
int value;
bio.read(reinterpret_cast<char *>(&value), sizeof(value));
cout << value;
86. File Positioner
文件位置指示器
-
File Positioner (文件位置指示器)
1.1. file positioner (fp):
A file consists of a sequence of bytes.(文件由字节序列构成)
File positioner is a special marker that is positioned at one of these bytes. (一个特殊标记指向其中一个字节)
1.2. A read or write operation takes place at the location of the file positioner. (读写操作都是从文件位置指示器所标记的位置开始)
When a file is opened, the fp is set at the beginning. (打开文件,fp指向文件头)
When you read or write data to the file, the file pointer moves forward to the next data item. (读写文件时,文件位置指示器会向后移动到下一个数据项)
1.3. File Positioner(文件位置指示器)的其它说法
File Pointer(文件指针):易与C语言的FILE* 混淆
File Cursor(文件光标):借用数据库中的“光标”概念
-
Example of File Positioner
aFileStream.get() ---> fp = fp + 1
87. Random Access File
随机访问文件
-
Random Access (随机访问)
1.1. Random Access means one can read/write anywhere inside a file(随机访问意味着可以读写文件的任意位置)
1.2. How?
We are able to know where the file positioner is. (我们能知道文件定位器在什么位置)
We are able to move the file positioner inside the file (我们能在文件中移动文件定位器)
Maybe we need two file positioners : one for reading, another for writing
1.3. 相关函数
· | For reading (**读文件时用)** | For writing(**写文件时用)** |
---|---|---|
获知文件定位器指到哪里 | tellg(); tell是获知,g是get表示读文件 | tellp(); tell是获知,p是put表示写文件 |
移动文件定位器到指定位置 | seekg(); seek是寻找,g是get表示读文件 | seekp(); seek是寻找,p是put表示写文件 |
-
seek的用法
2.1. seek的原型
xxx_stream& seekg/seekp( pos_type pos );
xxx_stream& seekg/seekp( off_type off, std::ios_base::seekdir dir);
seekdir 文件定位方向类型 | 解释 |
---|---|
std::ios_base::beg | 流的开始;beg = begin |
std::ios_base::end | 流的结尾 |
std::ios_base::cur | 流位置指示器的当前位置;cur = current |
例子 | 解释 |
---|---|
seekg(42L); | 将文件位置指示器移动到文件的第42字节处 |
seekg(10L, std::ios::beg); | 将文件位置指示器移动到从文件开头算起的第10字节处 |
seekp(-20L, std::ios::end); | 将文件位置指示器移动到从文件末尾开始,倒数第20字节处 |
seekp(-36L, std::ios::cur); | 将文件位置指示器移动到从当前位置开始,倒数第36字节处 |
88. Operators and Functions
运算符与函数
-
Special Operators Usage with Objects (与对象一起用的运算符)
1.1. string类:使用“+”连接两个字符串
string s1("Hello"), s2("World!");
cout << s1 + s2 << endl;
1.2. array 与 vector类:使用[] 访问元素
array<char, 3> a{};
vector<char> v(3, 'a'); //'a', 'a', 'a'
a[0] v[1] = 'b';
1.3. path类:使用“/”连接路径元素
std::filesystem::path p{};
p = p / "C:" / "Users" / "cyd";
-
The operator vs function (运算符与函数的异同)
2.1. 运算符可以看做是函数
2.2. 不同之处
2.2.1. 语法上有区别
3 * 2 //中缀式
*3 2 //前缀式
multiply ( 3, 2) ; //前缀式
3 2 * //后缀式(RPN)
2.2.2. 不能自定义新的运