C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 2(四)
达式)是不是常量表达式由它的数据类型和初始值共同决定:
?
const int max_files = 20; // 常量表达式
const int limit = max_files + 1; // 常量表达式
int staff_size = 27; // 不是常量表达式
const int sz = get_size(); // 不是常量表达式
C++11中,我们可以将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
?
5. 尽管指针可以定义成constexpr,但是它的初始值却受到严格的限制,必须是nullptr或者0,或者是存储于某个固定地址中的对象。还必须明确的一点事,限定符constexpr仅对指针有效,与指针所指的对象无关:
?
const int *p = nullptr; // p是一个指向整型常量的指针
constptr int *q = nullptr; // q是一个指向整型变量的常量指针
?
?
Chapter 2.5
1. C++11引入了一种新的定义类型别名的方法:
?
using MyInt = int;
2. 当指代复合类型的类型别名与const一起使用时,可能会产生意想不到的结果:
?
using pstring = char*;
const pstring cstr = nullptr; // cstr是指向char的常量指针
来看上述代码,当遇到一条使用了类型别名的声明语句时,很多人常常会错误的把类型别名替换成它本来的样子来理解它:
?
const char *cstr = nullptr;
这种理解是错误的。声明语句中用到pstring时,其基本数据类型是char*,是一个指针。而用char*替换重写了之后,基本数据类型就变成了char。所以,在理解使用类型别名的声明语句时,要特别注意这一点。
?
3. C++11引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。auto定义的变量必须有初始值。使用auto也能在一条语句中声明多个变量,但因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一致:
?
auto i = 0, *p = &i; // 正确:i是整数,p是整型指针
auto sz = 0, pi = 3.14; // 错误:sz和pi的类型不一致
4. 使用auto的时候要注意以下一些规则:当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:
?
int i = 0, &r = i;
auto a = r; // a是一个整数
auto一般会忽略掉顶层const,而保留底层const:
?
const int ci = 42;
auto b = ci; // b是一个整数(ci的顶层const特性被忽略)
auto e = &ci; // e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
设置一个类型为auto的引用时,初始值中的顶层const会被保留:
?
const int ci = 42;
auto &r = ci; // r是一个常量引用
5. C++11标准引入了类型说明符decltype,它的作用是返回它的操作数的类型:
?
decltype(f()) sum = x;
在上面的代码中,编译器并不会调用函数f,而是使用当函数f被调用时的返回值类型作为sum的类型。decltype处理顶层const和引用的方式与auto不同,如果decltype使用的表达式是一个变量,则它会返回该变量的类型(包括顶层const和引用):
?
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x的类型是const int
decltype(cj) y = x; // y的类型是const int&,绑定到x
如果decltype使用的表达式不是一个变量,则它将返回表达式结果对于的类型。一些表达式会导致decltype产生一个引用类型,通常来说,返回引用类型的表达式是那种能产生一条赋值语句的左值的表达式:
?
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // b是int类型
decltype(*p) c; // 错误:c是int&类型,必须初始化
正如我们所看到的,*p得到指针p所指的对象,并且该对象可以赋值,所以,decltype(*p)产生的是int&,而不是int。
?
有一种情况需要特别注意,如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型。如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式,而变量是一种可以作为赋值语句左值的特殊表达式,因此,这样decltype就会得到引用类型:?
int i = 42;
decltype((i)) d = i; // d是int&
?
?
Chapter 2.6
1. C++11标准规定,可以为类的数据成员提供一个类内初始值:
?
class CItem
{
? ? unsigned unitsSold = 0;
};
2. 预处理器是在编译之前执行的一段程序。
?
3. 预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理变量。预处理变量不遵循C++语言中关于作用域的规则,所以预处理变量在整个程序中必须唯一。
?
?
?
Exercises Section 2.1.3?
Q_1. Using escape sequences, write a program to print 2M followed by a newline. Modify the program to print 2, then a tab, then an M, followed by a newline.
?
A_1.?
?
复制代码
#include
?
int main()
{
? ? std::cout << "2\115" << '\12';
?
? ? return 0;
}
复制代码
复制代码
#include
?
int main()
{
? ? std::cout << '2' << '\t' << '\115' << '\n';
?
? ? return 0;
}
复制代码
?
?
Exercises Section 2.3.2
Q_1. Write code to change the value of a pointer. Write code to change the value to which the pointer points.
?
A_1.?
?
复制代码
#include
?
int main()
{
? ? int value = 0;
? ? int *pValue = &value;
?
? ? // 更改指针所指对象的值
? ? *pValue = 100;
?
? ? // 更改指针的值
? ? pValue = nullptr;
?
? ? return 0;
}
复制代码
?
?
Exercise