C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 2(二)

2015-01-27 06:14:56 · 作者: · 浏览: 33
型和字符型字面值的默认类型:
?
?
?
?
?
Chapter 2.2
1. C++中的每个变量都有其数据类型,数据类型决定着变量所占内存空间的大小和布局方式、该内存空间能够存储的值的范围、以及变量能参与的运算。
?
2. 当一次定义了两个或多个变量时,对象的名字随着定义也就马上可以使用了。因此,在同一条定义语句中,可以用先定义的变量值去初始化后定义的其他变量:
?
double price = 109.99, discount = price * 0.16;
3. 初始化与赋值是两个完全不同的操作。初始化的含义是创建变量时赋予其一个初始值。而赋值的含义是把对象的当前值擦除,用一个新值来替代。
?
4. 在C++11标准中,可以用花括号来初始化变量,这种初始化形式被称为列表初始化:
?
int units_sold = {0};
int units_sold{0};
当列表初始化用于内置类型的变量时,有一个重要特点:如果初始值存在丢失信息的风险,则编译器会报错:
?
long double ld = 3.1415926536;
int a{ld}, b = {ld}; ?// 编译错误:存在丢失信息的风险
int c(ld), d = ld; ? ?// 编译正确:但值被截断了
5. 如果定义变量时没有指定初始值,则变量会默认初始化:
?
(1). 如果是内置类型的变量,当它定义于任何函数体之外时,将被初始化为0。当它定义在函数体内部时,将不被初始化
(2). 每个类各自决定其初始化对象的方式
6. 变量声明规定了变量的类型和名字,在这一点上定义与之相同。但除此之外,定义还申请存储空间,并且可能会为变量赋一个初始值。
?
7. 声明一个变量而非定义它,就在变量名前添加关键字extern:
?
extern int i; ?// 声明
int j; ? ? ? ? ? ?// 定义
8. 任何包含了显示初始化的声明即成为定义。因此,extern语句如果包含初始值也就不再是声明了:
?
extern double pi = 3.1416; ?// 定义
在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。
?
9. 变量能且只能被定义一次,但是可以被多次声明。
?
10. C++中的作用域有如下几级:
?
全局作用域:全局作用域内的名字在整个程序的范围内都可使用
类作用域:名字定义在类的内部
命名空间作用域:名字定义在命名空间内部
块作用域:名字定义在块的内部。从声明位置开始直至声明语句所在的作用域末端为止都是可用的
11. 作用域能彼此包含,被包含的作用域称为内层作用域,包含着别的作用域的作用域称为外层作用域。作用域中一旦声明了某个名字,它所嵌套着的所有作用域都能访问该名字。同时,允许在内层作用域中重新定义外层作用域已有的名字。
?
?
?
Chapter 2.3
1. 我们无法令引用重新绑定到另外一个对象,因此引用必须初始化。
?
2. 引用并非对象,它只是为一个已经存在的对象所起的另外一个名字。因为引用本身不是一个对象,所以不能定义引用的引用。
?
3. 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
?
4. 指针与引用相比有几个不同点:其一,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。其二,指针无须在定义时赋初值。
?
5. 和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
?
6. 因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。
?
7. 指针存储的值可以是以下四种状态之一:
?
(1). 指向一个对象
(2). 指向一个对象所占空间末尾的下一个位置
(3). 空指针
(4). 无效指针
8. C++11引入了nullptr,可以初始化一个指针,表示空指针。它是一种特殊类型的字面值,可以被转换成任意其他的指针类型。
?
9. void*是一种特殊的指针类型,可用于存放任意对象的地址。
?
10. 变量的定义包括一个基本数据类型和一组声明符。在同一条定义语句中,虽然基本数据类型只有一个,但是声明符的形式却可以不同:
?
// i是一个int类型的变量,p是一个int类型的指针,r是一个int类型的引用
int i = 0, *p = &i, &r = i;
11. 指针是对象,所以存在对指针的引用:
?
int i = 42;
int *p = nullptr;
int *&r = p; ?// r是一个对指针p的引用
r = &i; ? ? ? // r引用了指针p,所以就是令p存放i的地址
*r = 0; ? ? ? // r引用了指针p,所以就是解引用指针p,得到i,将i的值改为0
?
?
Chapter 2.4
1. 引用的类型必须与其所引用对象的类型一致,但是有两个例外。第一个就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。特别是,允许为一个常量引用绑定非常量的对象、字面值,甚至是一个表达式:
?
复制代码
int i = 42;
const int &r1 = i;
const int &r2 = 42;
const int &r3 = r1 * 2;
?
double d = 3.14;
const int &r4 = d;
复制代码
2. 指针的类型必须与其所指对象的类型一致,但是有两个例外。第一个就是允许令一个指向常量的指针指向一个非常量对象:
?
double dval = 3.14;
const double *ptr = &dval;
3. 我们使用名词顶层const(top-level const)表示一个对象本身是常量,顶层const对任何数据类型都适用,如算术类型、类、指针等。而名词底层const(low-level const)用于指针或引用这些复合类型的基本类型,例如表示指针所指的对象是一个常量,引用所绑定的对象是一个常量。
?
当执行对象的拷贝操作时,顶层const会被忽略:
int i = 0;
const int ci = 42;
i = ci; ?// ci是顶层const,被忽略
拷贝操作并不会改变被拷贝对象的值,因此,拷入和拷出的对象是不是常量都没什么影响。
另一方面,底层const却不容忽视。当我们拷贝一个对象时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换,通常来说,非常量可以转换为常量,反之则不行:
int i = 0;
const int* const p = &i; // p3既是顶层const,又是底层const
int *p1 = p; // 错误:p包含底层const,但p1却没有
const int &r = i; // 正确:const int&可以绑定到普通int上,反之int&却不可以绑定到const int上
4. 常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。一个对象(或表