C++ Primer读书笔记梳理系列(一)
第二章 变量和基本类型
引用和指针
-
引用就是对象的别名(不是对象),之后不能被修改,必须初始化,类型必须进准匹配,且不能与表达式的结果匹配
int &ref1 = 10; //错 double a = 3.14; int &ref2 = a; //错,类型没有精确匹配 int b = 10; int &ref3 = a+10; //错,不能与表达式的计算结果绑定
-
指针与引用不同,是一个独立的对象,它的值是其他对象的地址
注意:&符号在等号左边表示引用,在右边表示取地址符。
-
可以对指针进行引用(指针是对象),反之不行
const 限定符
-
可以参考Efective C++ 条款3
-
常量表达:只值不会被改变,并且在编译过程中就能够计算结果的表达式;表达式是不是常量表达式由它的数据类型和初始值共同决定
const int a = 20; //是 const int b = a+1; // 是 int c = 27; //不是,因为int const int d = get_size(); //不是,因为在运行时才能得到d的值
-
constexpr变量
-
系统很复杂时,我们很难分辨一个初始值到底是不是常量表达式,所以C++11新标准想了个办法,允许将变量声明为constexpr类型来让编译器验证变量的值是否是一个常量表达式
constexpr int a = 20; //对 constexpr int b = a + 1; //对 constexpr int sz = size(); //只有当size是一个constexpr函数时才正确
第三章 字符串、向量和数组
命名空间的using声明
-
含using声明
using namespace std; //这样就可以访问std中所有的名字,但是很多用不到, //可能程序开销会变大
-
头文件不应该包含using 声明
我们用头文件一般是自定义数据类型吧(有待讨论) 因为头文件的内容在编译时会被拷贝到所有引用它的文件中去,如果头文件中有某个using声明,那么每个使用了该头文件的文件就都会有这个声明,很有可能产生一些冲突。
数组与多维数组
-
只有在用字符串字面值初始化数组时,编译器会在最后面加一个空字符’\0’
char a1[] = {'C', '+', '+'}; //列表初始化,后面没有空字符 char a2[] = "C++"; //自动添加空字符 char a[3] = "C++"; //错误:维度不够,没办法存放空字符
-
编译器会自动将数组名字替换为指向数组首元素的指针
第四章 表达式
基础
-
这里重点讲一下左值与右值
定义:当一个对象被用作右值的时候,用的是对象的值;当对象被用作左值的时候,用的是对象的身份。
原则:在需要右值的地方可以用左值代替,但不能把右值当成左值使用,也就是说,身份可以当值,值不能表示身份。
如何理解:身份就是内存中的位置,值就是内存中的内容,你知道了左值,也就是内存中的位置,当然可以拿到那个内容,所以左值能代替右值,但是你知道了内容,你是找不到地址的,因为可能很多内存地址的内容都是这个右值啊。
赋值运算符需要左值作为其左侧运算对象,得到的结果也是左值
取地址作用于左值,返回一个指向该运算对象的指针,这个指针是右值
内置解引用,下标,迭代器解引用的求值结果都是左值
递增递减作用于左值,前置版本例如++i得到结果也是左值
第五章 语句
try语句块和异常处理
异常是指存在于运行时的反常行为,而且这些行为超出了函数正常功能的范围,就是说函数无法处理了,例如失去数据库连接以及遇到意外输入等。
-
throw表达式
if(item1.isbn() != item2.isbn()) { throw runtime_error("不是同一种书");//一旦抛出异常后,程序就把控制权转移给能处理该异常的代码。 类型runtime_error是标准库异常类型的一种 } cout << item1 + item2;
-
try语句块
while(cin >> item1 >> item2) { try //执行相加,不行抛异常 { if(item1.isbn() != item2.isbn()) { throw runtime_error("不是同一种书"); } cout << item1 + item2; } catch(runtime_error err) { cout << err.what() << "再试一次?请输入yes或者 no" << endl; //what是库里的一个函数 string str; cin >> str; if(!cin || str == "no") //如果没输入或者输入no,就跳出循环,结束程序 { break; } }
如果没有找到匹配的catch子句,程序会转到terminat库函数,导致程序非正常退出。
第六章函数
函数匹配
-
注意函数调用产生的二义性
void f(int, double); void f(double, int); int main() { f(1,1); //调用有二义性 return 0; }
-
函数指针
函数指针指向的是函数,不是对象
第七章 类
-
这里着重注意构造函数,参数列表相关问题
-
如果定义了其他的构造函数,最好也提供一个默认构造函数(因为编译器不会产生)
class NoDefault { public: NoDefault(const string &); //定义了构造函数,但没有默认构造函数,而且编译器不会生成,这样这个类本身不会有问题,但是用起来很容易出问题 }; struct A { NoDefault a; }; A a; //你这样看着挺正常,A没有写构造函数,于是编译器会自动生成默认构造函数去初始化成员变量,可惜啊,这个成员变量的 //类型是类类型NoDefault,而这个该死的类类型又没有默认构造函数,还不让编译器自己生成,于是就报错了 //还有一种错误是这样的: struct B { B(){} NoDefault b; //b作为类类型成员,在构造函数没有被初始化,于是它会调用默认构造函数初始化,结果该死的NoDefault没有默认构造函数 };
注意,没有默认构造函数的类型,要在初始化列表中初始化
-
加explicit关键字就可以阻止隐式转换,注意,explicit关键字只对类内的转换构造函数有用,而且被声明为explicit的构造函数只能用于直接初始化,不能拷贝初始化:
class Sales_data { public: Sales_data() = default; explicit Sales_data(const string &s): bookNo(s){} explicit Sales_data(istream&); }; Sales_data item; string b = "1" item.combine(b); //这样就不行了 explicit Sales_data::Sales_data(istream& is){} //这样也不行,在外面了 Sales_data item1(b); //这样可以 Sales_data item2 = item1; //不行,explicit声明的不能拷贝初始化 //但是,多事C++又说我们还是可以强行转换: item.combine(Sales_data(b)); //可以 item.combine(static_cats<Sales_data>(cin)); //可以
第八章 IO库
IO类
- IO处理类型
- iostream定义了用于读写流的基本类型
- fstream定义了读写命名文件的类型
- sstream定义了读写内存string对象的类型
- IO对象不能拷贝或赋值
文件输入输出
-
头文件fstream定义了三个类型来支持文件IO:
- ifstream:从一个给定文件读取数据
- ofstream:向一个给定文件写入数据
- fstream:读写给定文件
-
使用文件流对象
ifstream input(record); //打开销售记录文件,关联到input ofstream output(out); //打开输出文件 Sales_data total; //保存销售额总量 if(read(input, total)) //读取第一条销售记录 { Sales_data trans; //保存下一条 while(read(input, trans)) { if(total.isbn() == trans.isbn()) { total.combine(trans); //同一条,加上去 } else { print(output, total) << endl; //不同的,输出前一条,刷新缓存 total = trans; //准备搞下一条 } } print(output, total) << endl; //打印最后一条 } else { cerr << "没数据啊老板" << endl; }
-
成员函数open和close
string ifile = "f"; ifstream in(ifile); //构建一个ifstream并打开f文件 ofstream out; out.open(ifile + "1"); //打开指定文件f1,out与f1关联 if(out) //如果打开成功(文件不能被连续打开) { in.close(); //关闭文件f in.open(ifile + "2"); //打开f2文件 } else { cerr << "文件不存在" << endl; }
参考
- C++ Primer 第五版
- C++ Primer