自己写的C++11 Primer Plus 学习笔记,如有雷同不胜荣幸,如有错误敬请指正
1. 友元,异常和其他
1. 嵌套类: 在另一个类中声明的类
嵌套类,结构和枚举的作用域特征| 声明位置 | 包含它的类是否可以使用它 | 从包含它的类派生而来的类是否可以使用它 | 在外部是否可以使用 |
|---|---|---|---|
| 私有部分 | 是 | 否 | 否 |
| 保护部分 | 是 | 是 | 否 |
| 公有部分 | 是 | 是 | 是,通过类限定符来使用 |
2. 异常
abort()的典型实现是向标准错误流(即:cerr使用的错误流)发送消息abnormal program termination(程序异常终止),然后终止程序(是否刷新问价缓冲区取决于实现)。exit()刷新文件缓冲区,但不显示消息。
异常处理的三个组成部分:
- 引发异常
- 使用处理程序捕获异常
- 使用 try 块
**异常规范(C++11已摒弃,推荐:关键字 noexcept 指出函数不会引发异常)
double harm(double a) throw(bad_thing); //may throw bad_thing exception
double marm(double) throw(); //doesn't throw an exception
///////////////////////
double marm() noexcept; //marm() doesn't throw an exception- 1
- 2
- 3
- 4
- 5
其中的 throw() 就是异常规范,它可能出现在函数原型和函数定义中,可包含类型列表,也可不包含
异常规范作用:
- 告诉用户可能需要使用
try块,当然也可以在注释中指出 - 让编译器添加执行运行阶段检查的代码,检查是否违反了异常规范
栈解退: 当函数由于异常(不是由于返回)而终止,则程序也将释放栈中的内存,但不会释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于 try 块中的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。(如果栈解退,则引发异常后,对于中间函数调用放在栈中的自动类型对象,其析构函数将不会被调用)
引发异常时,编译器总是创建一个临时拷贝,即使异常规范和 catch 块中指定的是引用
引用作为返回值的原因: 基类引用可以执行派生类对象。假设有一组通过继承关联起来的异常类型,则在异常规范中只需列出一个基类引用,它将与任何派生类对象匹配。
假设有一个异常类层次结构,并要分别处理不同异常类型,则使用基类引用将能够捕获任何异常对象;而使用派生类对象只能捕获它所属类及从这个类派生而来的类对象。
可以使用省略号来表示异常类型,从而捕获异常:
catch(...){ //statements }; //catches any type exception - 1
重新定义:
#include<exception>
class bad_hmean : public std::exception
{
public:
const char * what(){return "bad arguments to hmean()";}
...
};
class bad_gmean : public std::exception
{
public:
const char * what(){return "bad arguments to gmean()";}
...
};
////////////
try{
...
}catch(std::exception & e)
{
cout << e.what() << endl;
...
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
存在浮点类型可以表示的最小非零值,计算结果比这个值还小时将导致下溢错误;整形和浮点型都可能发生上溢错误,当计算结果超过了某个类型能够表示的最大数量级时,将发生上溢错误。
要捕获所有异常(预期和意外异常):
- 首先确保异常头文件的声明可用:
#include<exception>
using namespace std;
- 然后,设计一个替代函数,将意外异常转换为 bad_exception 异常,该函数原型如下:
void myUnexpected()
{
throw std::bad_exception; //or just throw
}
仅使用 throw ,而不是指定异常将导致重新引发原来的异常。然而,如果异常规范中包含了这种类型,则该异常将被 bad_exception 对象所取代 - 接下来在程序开始位置,将意外异常操作指定为调用该函数:
set_unexcepted(myUnexpected); - 最后,将 bad_exception 类型包含在异常规范中,并添加如下 catch 块序列:
double Argh(double,double) throw (out_of_bounds,bad_exception);
...
try{
x = Argh(a,b);
}catch(out_of_bounds & ex)
{
...
}catch(bad_exception & ex)
{
...
}
3. RTTI(运行阶段类型识别:Runtime Type Identification): 旨在为程序在运行阶段确定对象的类型提供一种标准方式。
C++ 支持 RTTI 的元素:
- 如果可能的话,
dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类指针;否则,该运算符返回0——空指针 typeid运算符返回一个指出对象的类型的值type_info结构存储了有关特定类型的信息
dynamic_cast运算符: Superb * pm = dynamic_cast<Superb *>(pg);
typeid 运算符和 type_info 类:
- typeid 运算符使得能够确定两个对象是否为同种类型,可接受两个参数:① 类名 ② 结果为对象的表达式 。typeid 运算符返回一个对 type_info 对象的引用,例如:如果 pg 指向的是一个 Mag 对象,则下述表达式的结果为true,否则为false:
typeid(Mag) == typeid(*pg) - type_info 类的实现随厂商而异,但包含一个 name() 成员,该函数返回一个随实现而异的字符串:通常是类的名称
4. 类型转换运算符
- dynamic_cast
- const_cast
- static_cast
- reinterpret_cast
dynamic_cast: dynamic_cast<type-name>(expression),该运算符的作用是使得能够在类层次结构中进行向上转换,而不允许其他转换
const_cast: const_cast <type-name>(expression),该运算符的作用是改变值为 const 或 volatile
(type-name 与 expression 的类型必须相同)
High bar;
const High * pbar = &bar;
...
High * pb = const_cast<High *> (pbar); //valid
const Low * pl = const_cast<const Low *> (pbar); //invalid- 1
- 2
- 3
- 4
- 5
static_cast: static_cast <type-name>(expression),仅当 type_name 可被隐式转换为 expression 所属的类型或 expression 可被隐式转换为 type_name 所属的类型时,上述转换才是合法的。
High bar;
Low blow;
...
High * pb = static_cast<High *> (&blow); //valid upcast
Low * pl = static_cast<Low *> (&bar); //valid downcast
Pond * pmer = static_cast<Pond *> (&blow); //invalid,Pond unrelated- 1
- 2
- 3
- 4
- 5
- 6
reinterpret_cast: reinterpret_cast <type-name>(expression),用于天生危险的类型转换
struct dat {short a; short b;};
long value = 0xA224B118;
dat * pd = reinterpret_cast<dat *> (&value);
cout << hex << pd->a; //display first 2 bytes of value- 1
- 2
- 3
- 4
通常,这样的转换适用于依赖实现的底层编程技术,是不可移植的。例如:不同系统在存储多字节整形时,可能以不同的顺序存储其中的字节。
2. string 类和标准模板库
1. string 类
string 类的构造函数(string 实际上是模板具体化
basic_string<cahr> 的一个 `typedef)
| 构造函数 | 描述 |
|---|---|
| string(const cahr * s) | 将 string 对象初始化为 s 指向的 NBTS |
| string(size_type n,cahr c) | 创建一个包含 n 个元素的 string 对象,其中每个元素都被初始化为字符 c |
| string(const string & str) | 将一个 string 对象初始化为 string 对象 str (复制构造函数) |
| string() | 创建一个默认的string对象,长度为0(默认构造函数) |
| string(const char * s,size_type n) | 将 string 对象初始化为 s 指向的 NBTS 的前 n 个字符,即使超过了 NBTS 结尾 |
| template< class Iter> string(Iter begin,Iter end) | 将 string 对象初始化为区间[begin,end)内的字符,其中begin和end行为就像指针,用于指定位置,范围包括begin在内,但不包括end |
| string(const string & str,string size_type pos=0,size_type n=npos) | 将一个string 对象初始化为对象 str 中从位置 pos 开始到结尾的字符,或从位置 pos 开始的 n 个字符 |
| string(string && str) noexcept | 它将一个string对象初始化为string对象str,并可能修改str(移动构造函数) |
| string(initializer_list il) | 它将一个string对象初始化为初始化列表il中的字符 |
**string 版本的 getline() 函数从输入中读取字符,并将其储存到目标string中,直到发生下列三种情况之一:
- 到达文件尾,在这种情况下,输入流的
eofbit将被设置,这意味着方法fail()和eof()都将返回 true; - 遇到分界字符(默认为
\n),在这种情况下,将把分界字符从输入流中删除,但不储存它 - 读取的字符数达到最大允许值(
string::npos(通常是无符号 int 或 无符号 long 的最大值) 和可供分配的内存字节数中较小的一个),在这种情况下,将设置输入流的failbit,这意味着方法fail()将返回 true
find() 方法
| 方法原型 | 描述 |
|---|---|
| size_type find(const string & str,size_type pos=0) const | 从字符串的 pos 位置开始,查找子字符串 str。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回 string::npos |
| size_type find(const char * s,size_type pos=0)const | 从字符串的 pos 位置开始,查找子字符串 s。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回 string::npos |
| size_type find(const char * s,size_type pos=0,size_type n) | 从字符串的 pos 位置开始,查找 s 的前 n 个字符组成的子字符串。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回 string::npos |
| size_type find(char ch,size_type pos=0)const | 从字符串的 pos 位置开始,查找字符 ch。如果找到,则返回该字符首次出现的位置;否则,返回 string::npos |
string 库还提供了相关方法:rfind(),find_last_of(),find_first_of(),find_first_not_of(),find_last_not_of(),它们重载函数特征标都与 find() 方法相同。rfind() 方法查找子字符串或字符最后一次出现的位置;find_first_of() 方法在字符串中查找参数中任何一个字符首次出现的位置;find_last_of() 查找最后一次出现的位置;find_first_not_of() 在字符串中查找第一个不包含在参数中的字符
2. 智能指针模板类(智能指针是行为类似于指针的模板类对象)
- auto_ptr
- unique_ptr
- shared_ptr
普通指针过期时,其所占据的内存将被释放,但其所指向的内存将不会被释放(因为其不是对象,无法调用其析构函数来删除其指向的内存)
这三个智能指针模板都定义了类似指针的对象,可以将 new 获得的地址赋给这种对象,其析构函数将使用 delete 来释放内存。因此,如果将 new 返回的地址赋给这些对象,将无需记住稍后释放这些内存:在智能指针过期时,这些内存将自动释放
避免程序删除一个对象两次:
- 定义赋值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本
- 建立所有权概念,对于特定的对象,只能有一个只能指针可拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后,让赋值操作转让所有权。这就是
auto_ptr和unique_ptr的策略,但unique_ptr的策略更严格 - 创建智能更高的指针,跟踪引用特定对象的指针数,称为引用计数。例如:赋值时,计数将加1,而指针过期时,计数将减1,仅当最后一个指针过期时,才调用 delete。这是
shared_ptr采用的策略。
unique_ptr 优于 auto_ptr:
auto_ptr<string> p1 = new string("auto"); //#1
auto_ptr<string> p2; //#2
p2 = p1; //#3- 1
- 2
- 3
在语句 #3 中,p2 接管 string 对象的所有权后,p1 的所有权将被剥夺。这样可防止 p1 和 p2 的析构函数试图删除同一个对象;但如果程序随后试图使用 p1,这将是坏事,因为p1 不再指向有效的数据。
unique_ptr<string> p3 = new string("auto"); //#4
unique_ptr<string> p4; //#5
p4 = p3; //#6;- 1
- 2
- 3
编译器认为语句 #6 非法,避免了 p3 不再指向有效的数据的问题。
程序试图将一个 unique_ptr 赋给另一个时,如果源 unique_ptr 是一个临时右值,编译器允许这样做;如果源 unique_ptr 将存在一段时间,编译器将禁止这样做:
unique_ptr<string> pu1 = new string("hi");
unique_ptr<string> pu2;
pu2 = pu1; //#1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string("you")); //#2 allowed- 1
- 2
- 3
- 4
- 5
同时,unique_ptr 还可用于数组的变体
使用 new 分配内存时,才能使用
auto_ptr与shared_ptr;不使用 new 或 new[] 分配内存时,不能使用unique_ptr
3. 标准模板库
① 模板类 vector
template<class T,class Allocator = allocator<T>>
calss vector{...- 1
- 2
如果省略该模板参数的值,则容器模板将默认使用 allocator 类(这个类使用 new 和 delete)
vector 模板使用动态内存分配,因此可以初始化参数来指出需要多少矢量
STL 容器的基本方法:
- size():返回容器中元素的数目
- swap():交换两个容器的内容
- begin():返回一个指向容器中第一个元素的迭代器
- end():返回一个表示超过容器尾的迭代器
- erase():删除矢量中给定区间的元素
4. 泛型编程
面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法。它们之间的共同点是抽象和创建可重用代码。泛型编程旨在编写独立于数据类的代码。
迭代器类型:
- 输入迭代器:可被程序用来读取容器中的信息。具体的说,对输入迭代器解除引用将使程序能够读取容器中的值,但不一定能让程序修改值。基于输入迭代器的任何算法都应当是单通行的,不依赖于前一次遍历时的迭代器值,也不依赖于本次遍历中前面的迭代器值
- 输出迭代器:指用于将信息从程序传输给容器的迭代器,解除引用让程序能修改容器值,而不能读取
- 正向迭代器:正向迭代器只使用 ++ 运算符来遍历容器;既可以使得能够读取和修改数据,也可以使得只能读取数据
- 双向迭代器:双向迭代器具有正向迭代器的所有特性,同时支持递减运算符
- 随机访问迭代器 :随机访问迭代器具有双向迭代器的所有特性,同时添加了支持随机访问的操作(如指针增加运算)和用于对于元素进行排序的关系运算符
| 迭代器功能 | 输入 | 输出 | 正向 | 双向 | 随机访问 |
|---|---|---|---|---|---|
| 解除引用读取 | 有 | 无 | 有 | 有 | 有 |
| 解除引用写入 | 无 | 有 | 有 | 有 | 有 |
| 固定和可重复排序 | 无 | 无 | 有 | 有 | 有 |
| ++i,i++ | 有 | 有 | 有 | 有 | 有 |
| –i i– | 无 | 无 | 无 | 有 | 有 |
| i[n] | 无 | 无 | 无 | 无 | 有 |
| i + n | 无 | 无 | 无 | 无 | 有 |
| i - n | 无 | 无 | 无 | 无 | 有 |
| i += n | 无 | 无 | 无 | 无 | 有 |
| i -= n | 无 | 无 | 无 | 无 | 有 |
从快到慢依次为编译时间,固定时间,线性时间
| 表达式 | 返回类型 | 满足正向迭代器要求的任何迭代器 | 编译时间 |
|---|---|---|---|
| X::iterator | 指向 T 的迭代类型 | 满足正向迭代器要求的任何迭代器 | 编译时间 |
| X::value_type | T | T 的类型 | 编译时间 |
| X u; | 创建一个名为u的空容器 | 固定 | |
| X() | 创建一个匿名的空容器 | 固定 | |
| X u(a); | 调用复制构造函数后u == a | 线性 | |
| X u = a; | 作用同 X u(a) | 线性 | |
| r = a; | X& | 调用赋值运算符后r == a | 线性 |
| (&a)->~X() | void | 对容器中的每个元素应用析构函数 | 线性 |
| a.begin() | 迭代器 | 返回指向容器第一个元素的迭代器 | 固定 |
| a.end() | 迭代器 | 返回超尾值迭代器 | 固定 |
| a.size() | 无符号整形 | 返回元素个数,等价于a.end()-a.begin() | 固定 |
| a.swap(b) | void | 交换 a 和 b 的内容 | 固定 |
| a == b | 可转换为 bool | 如果a和b的长度相同,且a中每个元素都等于(==为真)b中相应的元素,则为真 | 线性 |
| a != b | 可转换为bool | 返回 !(a==b) | 线性 |
| X u(rv) | 调用移动构造函数后,u 的值与 rv 的原始值相同 | 线性 | |
| X u = rv; | 作用同 X u(rv) | ||
| a = rv; | X & | 调用移动赋值运算符后,u的值与rv的原始值相同 | 线性 |
| a.cbegin() | const_iterator | 返回指向容器第一个元素的 const 迭代器 | 固定 |
| a.cend() | const_iterator | 返回超尾值 const 迭代器 | 固定 |
7种序列容器类型:
- vector:vector是数组的一种表示,它提供了自动内存管理功能,可以动态的改变vector对象的长度,并随着元素的添加和删除而增大和缩小。它提供了对元素的随机访问。在尾部添加和删除元素的时间是固定的,但在头部或中间插入和删除元素的复杂度为线性时间。它还是一个反转容器
- deque:表示双端队列,类似于vector,区别是从deque对象的开始位置插入和删除元素的时间是固定的
- list:表示双向链表,除了第一个和最后一个元素外,每个元素都与前后的元素相链接,这意味着可以双向遍历链表,与vector的区别是list在链表中任一位置进行插入和删除的时间都是固定的。因此,vector强调的是通过随机访问进行快速访问,而
list 强调的是元素的快速插入和删除 - forward:实现了但链表,在这个链表中,每个节点只链接到下一个节点而没有链接到前一个节点
- queue:是一个适配器类
- priority_queue:也是一个适配器类,与queue的区别是在 priority_queue 中,最大的元素被移到队首;外部区别是默认的底层类是vector
- stack:也是一个适配器类,它给底层类提供了典型的栈接口
- array:
关联容器(将值与键关联在一起,并使用键来查找值): set,multiset,map,multimap
优点:提供了对元素的快速访问;关联容器通常用于确定数据放置位置的算法,以便能够快速检索信息。
- set:其值类型与键相同,键是唯一的
- multiset:类似于set,只是可能有多个值的键相同
- map:值与键的类型不同,键是唯一的,每个键只对应一个值
- multimap:类似于map,只是可以与多个值相关联
无序关联容器: 也是将值与键关联起来,并使用键来查找值;底层差别在于,关联容器是基于数结构的,而无序关联容器是基于数据结构哈希表的,这旨在提高添加和删除元素的速度以及提高查找算法的效率(unordered_set,unordered_multiset,unordered_map,unordered_multimap)
5. 函数对象(函数符): 是可以以函数方式与 () 结合使用的任意对象,这包括函数名,指向函数的指针,重载了 () 运算符的类对象
函数符概念:
- 生成器是不用参数就可以调用的函数符
- 一元函数是一个参数可以调用的函数符
- 二元函数是用两个参数可以调用的函数符
- 返回 bool 值的一元函数是谓词
- 返回 bool 值的二元函数是二元谓词
| 运算符 | 相应的函数符 |
|---|---|
| + | plus |
| - | minus |
| * | multiplies |
| / | divides |
| % | modules |
| - | negate |
| == | equal_to |
| != | not_equal_to |
| > | greater |
| < | less |
| >= | greater_equal |
| <= | less_equal |
| && | logical_and |
| || | logical_or |
| ! | logical_not |
使函数成为自适应的原因是,它携带了标识参数类型和返回类型的 typedef 成员,这些成员分别是 result_type,first_argument_type,second_argument_type。
函数符自适应的意义是:函数适配器对象可以使用函数对象,并认为存在这些 typedef 成员
6. 算法
STL 将算法库分成:
- 非修改式序列操作:对区间中的每个元素进行操作,这些操作不修改容器的内容
- 修改式序列操作:对区间的每个元素进行操作,可以修改容易的内容;可以修改值,也可以修改值的排列顺序
- 排序和相关操作:包括多个排序函数和其他各种函数,包括集合操作
- 通用数字运算:包括将区间的内容积累,计算两个容器的内部乘积,计算小计,计算相邻对象差的函数
3. 输入,输出和文件
1. C++输入输出概述
输出时,程序首先填满缓冲区,然后把整块数据传输给硬盘,并清空缓冲区,已被下一批输出使用,这被成为刷新缓冲区(C++在用户按下回车键时刷新缓冲区)
- streambuf 类为缓冲区提供了内存,并提供了用于填充缓冲区,访问缓冲区内容,刷新缓冲区和管理缓冲区内存的类方法
- ios_base类表示流的一般特征,如是否可读取,是二进制流还是文本流等(存储了描述格式状态的信息,通过使用 ios_base 的成员函数,可以控制字段宽度和小数位数)
- ios 类基于 ios_base,其中包括了一个指向 streambuf 对象的指针成员
- ostream 类是从 ios 类派生而来的,提供了输出方法(ostream 类最重要的任务之一是将数值类型转换为以文本形式表示的字符值,ostream 将数据内部表示转换为由字符字节组成的输出流。由于ostream 类对于 cout 对象处理的输出流进行缓冲,所有输出不会立即发送到目标地址,而是被存储在缓冲区中,知道缓冲区填满。然后程序将刷新缓冲区,把内容发送出去,并清空缓冲区,以存储新的数据)
- istream 类也是从 ios 类派生而来的,提供了输入方法
- iostream 类是基于 istream 和 ostream 类的,因此继承了输入和输出方法
在程序中包含 iostream 文件将自动创建 8 个流对象(4 个用于窄字符流,4 个用于宽字符流):
- cin(wcin) 对象对应于标准输入流
- cout(wcout) 对象对应于标准输出流
- cerr(wcerr) 对象与标准错误流对应,可用于显示错误消息。这个流不会被缓冲,这意味着信息将直接被发送到屏幕
- clog(wclog) 对象也对应标准错误流,这个流被缓冲
| 常量 | 含义 |
|---|---|
| ios_base::boolalpha | 输入和输出 bool 值,可以为 true 或 false |
| ios_base::showbase | 对于输出,使用C++基数前缀(0,0x) |
| ios_base::showpoint | 显示末尾的小数点 |
| ios_base::uppercase | 对于16进制输出,使用大写字母,E表示法 |
| ios_base::showpos | 在正数前面加上 + |
| 第二个参数 | 第一个参数 | 含义 |
|---|---|---|
| ios_base::basefield | ios_base::dec | 使用基数 10 |
| ios_base::oct | 使用基数8 | |
| ios_base::hex | 使用基数16 | |
| ios_base::floatfield | ios_base::fixed | 使用定点计数法 |
| ios_base::scientific | 使用科学计数法 | |
| ios_base::adjustfield | ios_base::left | 使用左对齐 |
| ios_base::right | 使用右对齐 | |
| ios_base::internal | 符号或基数前缀左对齐,值右对齐 |
| 控制符 | 调用 |
|---|---|
| boolalpha | setf(ios_base::boolalpha) |
| noboolalpha | unsetf(ios_base::noboolalpha) |
| showbase | setf(ios_base::showbase) |
| noshowbase | unsetf(ios_base::noshowbase) |
| showpoint | setf(ios_base::showpoint) |
| noshowpoint | unsetf(ios_base::noshowpoint) |
| showpos | setf(ios_base::showpos) |
| uppercase | setf(ios_base::uppercase) |
| internal | setf(ios_base::internal,ios_base::adjustfield) |
| left | setf(ios_base::left,ios_base::adjustfield) |
| right | setf(ios_base::right,ios_base::adjustfield) |
| dec | setf(ios_base::dec,ios_base::adjustfield) |
| hex | setf(ios_base::hex,ios_base::adjustfield) |
| oct | setf(ios_base::oct,ios_base::adjustfield) |
| fixed | setf(ios_base::fixed,ios_base::adjustfield) |
| scientific | setf(ios_base::scientific,ios_base::adjustfield) |
**头文件 iomanip 最常用的控制符分别是 setprecision(),setfill(),setw(),它们分别用来设置精度,填充字符和字段宽度。setprecision() 控制符接受一个指定精度的正数参数,setfill() 控制符接受一个指定填充字符的 char 参数,setw() 控制符接受一个制定字符==字段宽度的正数参数
流状态: 由三个 ios_base 元素组成(eofbit,badbit,failbit),其中每个元素都是一位,可以是1(设置)或0(清除)。当 cin 操作到达文件末尾时,它将设置 eofbit;当 cin 操作未能读取到预期的字符时,它将设置 failbit(I/O失败也可能将 failbit 设置为 1);在一些无法诊断的失败破坏流时,badbit 元素将被设置。当全部三个状态位都设置为 0 时,说明一切顺利;程序可以检查流状态,并使用这种信息来决定下一步做什么
流状态| 成员 | 描述 |
|---|---|
| eofbit | 如果到达文件尾,则设置为1 |
| badbit | 如果流被破坏,则设置为1 |
| failbit | 如果输入操作未能读取预期的字符或输出操作没有写入预期的字符,则设置为1 |
| goodbit | 另一种表示 0 的方法 |
| good() | 如果流可以使用(所有位都被清除),则返回true |
| eof() | 如果 eofbit 被设置,则返回 true |
| bad() | 如果 badbit 被设置,则返回true |
| fail() | 如果 badbit或failbit 被设置,则返回true |
| rdstate() | 返回流状态 |
| exceptions() | 返回一个位掩码,指出哪些标记导致异常被引发 |
| exceptions(isostate ex) | 设置哪些状态将导致clear()引发异常 |
| clear(iostate s) | 将流状态设置为 s ;s 的默认值为0(goodbit);如果(restate()&exceptions())!=0,则引发异常 basic_ios::failure |
| setstate(iostate s) | 调用 clear(rdstate()|s)。这将设置与s中设置的位对应的流状态位,其他流状态位保持不变 |
(clear() 与 setstate() 都重置状态,但 clear() 将状态设置为它是参数,而setstate() 方法只是影响其参数中已设置的位)
cin.get(ch)与cin.get()exceptions() 方法返回一个位字段,它包含三位,分别对应 eofbit,badbit,failbit。修改流状态涉及 clear(),setstate(),这都将使用 clear()。修改流状态后,clear()方法将当前的流状态与exceptions() 返回的值进行比较。如果在返回值中某一位被设置,而当前状态中的对应位也被设置,则 clear() 将引发 ios_base::failure 异常。
| 特征 | cin.get(ch) | cin.get() |
|---|---|---|
| 传输输入字符的方法 | 赋给参数ch | 将函数返回值赋给ch |
| 字符输入时函数的返回值 | 指向 istream 对象的引用 | 字符编码(int 值) |
| 达到文件尾时函数的返回值 | 转换为 false | EOF |
| 方法 | 行为 |
|---|---|
| getline(char *,int) | 如果没有读取任何字符(但换行符被视为读取了一个字符),则设置 failbit;如果读取了最大数目的字符,且行中还有其他字符,则设置 failbit |
| get(char *,int) | 如果没有读取任何字符,则设置 failbit |
peek() 函数返回输入中的下一个字符,但不抽取输入流中的字符
gcount() 方法返回最后一个非格式化抽取方法读取的字符数
putback() 函数将一个字符插入到输入字符中,被插入的字符将是下一条输入语句读取的第一个字符|
2. 文件输入和输出
以默认模式打开文件进行输入将自动把文件的长度截断为零,这相当于清除已有的内容。
读取文件的要求与写入文件相识:
- 创建一个与 ifstream 对象来管理输入流
- 将该对象与特定的文件关联起来
- 以使用 cin 的方式使用该对象
| 常量 | 含义 |
|---|---|
| ios_base::in | 打开文件,以便读取 |
| ios_base::out | 打开文件,以便写入 |
| ios_base::ate | 打开文件,并移到文件尾 |
| ios_base::app | 追加到文件尾 |
| ios_base::trunc | 如果文件存在,则截短文件 |
| ios_base::binary | 二进制文件 |
| C++模式 | C模式 | 含义 |
|---|---|---|
| ios_base::in | “r” | 打开以读取 |
| ios_base::out | “w” | 等价于 ios_base::out | ios_base::trunc |
| ios_base::out | ios_base::trunc | “w” | 打开以写入,如果已经存在,则截短文件 |
| ios_base::out | ios_base::app | “a” | 打开以写入,只追加 |
| ios_base::out | ios_base::out | “r+” | 打开以读写,在文件允许的位置写入 |
| ios_base::out | ios_base::out | ios_base::trunc | “w+” | 打开以读写,如果已经存在,则首先截短文件 |
| c++mode | ios_base::binary | “cmodeb” | 以 C++mode(或相应的cmode)和二进制模式打开;例如:ios_base::in | ios_base::binary 成为 “rb” |
| c++mode | ios_base::ate | “cmode” | 以指定的模式打开,并移到文件尾。C 使用一个独立的函数调用,而不是模式编码 |
3. 内核格式化: 读取 string 对象中的格式化信息或将格式化信息写入 string 对象中。
- iostream 族支持程序与终端之间的 I/O
- fstream 族使用相同的接口提供程序和文件之间的 I/O
- sstream 族 使用相同的接口提供程序和string 对象之间的 I/O