笔记部分比较混乱只记录自己认为重要的点。
笔记
2.1 基本内置类型
2.1.1 算术类型
详见p30表格
2.1.2 类型转换
非布尔值转换为布尔值时,非零为true,0为false。
布尔值在算术表达中,true为1,false为0,不宜用在算术值中使用布尔值。
2.1.3 字面值常量
每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型。
如 :
42 整型十进制
042 整型八进制
0x42 整型十六进制
42.0 浮点型
“42” 字符串字面值
‘4’ 字符字面值
可通过添加前缀和后缀改变整型、浮点数、和字符字面值的类型
如
42 整型 int
42L 整型 long int
42ULL 整型 usigned long long
42.0L 浮点数 long double
布尔字面值:false和true
2.2 变量
变量提供一个剧名的、可供程序操作的存储空间。
2.2.1 变量定义
类型说明符 变量名(一个或多个)
如:
int a,b;
初始化
初始化不等同于赋值。
列表初始化:当用于内置类型的变量时,这种初始化形式有一个重要特点:如果我们使用列表初始化且初始值存在丢失信息的风险时,编译器将报错:
2.2.2 声明与定义的关系
声明(declaration)使得名字为程序所知
定义(definition)负责创建与名字关联的实体
extern int i;//声明而非定义
int j;//声明并定义了j
变量只能被定义一次,但可以被多次声明。
2.2.3 标识符
标识符(identifier)由字母、数字和下划线组成,必须以字母和下划线开头。长度没有限制,大小写字母敏感。
C++关键字详见p43
2.2.3 名字的作用域
全局作用域
块作用域
2.3 复合类型
符合类型是指基于其他类型定义的类型。
2.3.1 引用
引用即别名
引用一旦初始化完成,引用将和它的初始对象一直绑定在一起,无法重新绑定到另一对象
引用必须初始化
引用本身不是一个对象,不能定义引用的引用
2.3.2 指针
指针必须与它指向的对象严格匹配
空指针
几个生成空指针的方法
int *p1 = nullptr; // equivalent to int *p1 = 0;
int *p2 = 0; // directly initializes p2 from the literal constant 0
// must #include cstdlib
int *p3 = NULL; // equivalent to int *p3 = 0;
指针在条件表达式中,如果指针的值为0条件取false,否则为true。
void*指针
void指针可以存放任意对象的地址。
void指针可以用于和别的指针比较,作为函数的输入或输出,或者赋给另一个void 指针,但不能直接操作所指的对象,因为不知道对象到底是什么类型,可以做哪些操作。
2.3.3 理解符合类型的声明
理解一个变量类型到底是什么,最简单的方法就是从右往左读该变量的定义。离变量最近的符号(如符号&)对变量的类型有最直接的影响。
如:
int *p;
int *&r=p;
离r最近的符号是&,所以r是一个引用,声明符的其余部分用以确定r引用的类型是什么,符号*说明r引用的是指针。最后,声明的基本数据类型部分指出r引用的是一个int指针。
2.4 const限定符
const对象一旦创建后其值就不能再改变,所以const对象必须初始化。初始值可以是任意复杂的表达式。
默认状态下,const对象仅在文件内有效
当多个文件出现同名的const变量时,等同于在不同文件中分别定义了独立的变量。
如果不希望编译器为每个文件分别生成独立的变量,可以使用extern关键字。
2.4.1 const的引用
把引用绑定到const对象上,称之为常量引用(reference to const)。
对常量的引用不能改变它所绑定对象的值。、
初始化和对const的引用
常量引用可以绑定非常量对象、字面值、甚至是个一般表达式。
int i = 42;
const int &r1 = i; // we can bind a const int& to a plain int object
const int &r2 = 42; // ok: r1 is a reference to const
const int &r3 = r1 * 2; // ok: r3 is a reference to const
int &r4 = r * 2; // error: r4 is a plain, non const reference
double dval = 3.14;
const int &ri = dval;
编译器会把代码变成如下形式:
const int temp = dval; // create a temporary const int from the double
const int &ri = temp; // bind ri to that temporary
ri绑定了一个临时量对象
对const的引用可能引用一个非const的对象
必须认识到, 常量引用仅对可参与的操作做出了限定, 对于引用的对象本身是不个常量未作限定。 因为对象也可能是个非常量, 所以允许通过其他途径改变它的值:
int i = 42;
int &r1 = i; // r1 bound to i
const int &r2 = i; // r2 also bound to i; but cannot be used to change i
r1 = 0; // r1 is not const; i is now 0
r2 = 0; // error: r2 is a reference to const
2.4.2 指针和const
想要存放常量对象的地址,只能使用指向常量的指针
允许令一个指向常量的指针指向一个非常量对象,但该指针不能用于改变其所指对象的值。
const指针
常量指针必须初始化
2.4.3 顶层const
顶层const(top-level const表示指针本身时个常量
底层const(low-level const表示指针所指的对象时一个常量
更一般的,顶层const 表示任意对象时常量,这一点对任意数据类型都适用
底层const则与指针和引用等符合类型有关。
int i = 0;
int *const p1 = &i; // we can't change the value of p1; const is top-level
const int ci = 42; // we cannot change ci; const is top-level
const int *p2 = &ci; // we can change p2; const is low-level
const int *const p3 = p2; // right-most const is top-level, left-most is not
const int &r = ci; // const in reference types is always low-level
当拷贝对象时,顶层const不受影响。另一方面,底层const的限制却不能忽略。
2.4.4 常量表达式
常量表达式(const expression)是指值不会改变并且在编译过程中就能得到计算结果的表达式。
constexpt变量
一般来说,如果认定变量是一个常量表达式,那就把它生命成constexpr类型。声明成constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
constexpr int mf = 20; // 20 is a constant expression
constexpr int limit = mf + 1; // mf + 1 is a constant expression
constexpr int sz = size(); // ok only if size is a constexpr function
指针和constexpr
限定符constexpr只对指针有效,与所指向的对象无关
const int *p = nullptr; // p is a pointer to a const int
constexpr int *q = nullptr; // q is a const pointer to int
constexpr把它所定义的对象置为了顶层const
2.5 处理类型
2.5.1 类型别名
传统方法使用typedef关键字
typedef double wages; // wages is a synonym for double
typedef wages base, *p; // base is a synonym for double, p for double*
新标准使用using声明
using SI = Sales_item; // SI is a synonym for Sales_item
2.5.2 auto类型说明符
auto能让编译器替我们去分析表达式所属的类型。
使用auto也能在一条表达式中声明多个变量。因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样。
复合类型、常量和auto
当引用被用作初始值时,真正参与初始化的其实是引用对象的值,此时编译器以引用的对象作为auto的类型
int i = 0, &r = i;
auto a = r; // a is an int (r is an alias for i, which has type int)
auto一般会忽略掉顶层const,同时底层const会保留下来,比如当初始值是一个指向常量的指针时:
const int ci = i, &cr = ci;
auto b = ci; // b is an int (top-level const in ci is dropped)
auto c = cr; // c is an int (cr is an alias for ci whose const is top-level)
auto d = &i; // d is an int*(& of an int object is int*)
auto e = &ci; // e is const int*(& of a const object is low-level const)
如果希望推断出的auto类型是一个顶层const,需要明确指出:
const auto f = ci; // deduced type of ci is int; f has type const int
引用类型也可以设置为auto,原来的初始化规则仍然适用
2.5.3 decltype类型指示符
decltype的作用是选择并返回操作数的数据类型
如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内):
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x has type const int
decltype(cj) y = x; // y has type const int& and is bound to x
decltype(cj) z; // error: z is a reference and must be initialized
引用从来都作为所指的对象的同义词出现,只有用decltpye处是一个例外
decltype和引用
有些表达式将向的decltype返回一个引用类型,一般来说当这种情况发生时,意味着该表达式的结果对象能作为一条赋值语句的左值:
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // ok: addition yields an int; b is an (uninitialized) int
decltype(*p) c; // error: c is int& and must be initialized
如果表达式的内容是解引用操作,则decltype将得到引用类型。
decltype((variable)(注意是双层括号)的结果永远是引用,而decltype(variable)结果只有当variable本身就是一个引用时才是引用。
// decltype of a parenthesized variable is always a reference
decltype((i)) d; // error: d is int& and must be initialized
decltype(i) e; // ok: e is an (uninitialized) int
2.6 自定义数据结构
关键字struct
预编译处理
预处理变量无视C++语言中关于作用域的规则
头文件保护,防止重复包含。
练习答案
Exercise 2.1: What are the differences between int, long, long long,
and short? Between an unsigned and a signed type? Between a float and
a double?
略,详见书。
Exercise 2.2: To calculate a mortgage payment, what types would you use
for the rate, principal, and payment? Explain why you selected each type.
选择double较合适,利率本金付款皆不是整数,所以不选取整数类型;double和float相比精度更高,运算成本相差无几。double的所容纳的数一般而言足够,不必要选long double。
Exercise 2.3: What output will the following code produce?
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;//42-10,32
std::cout << u - u2 << std::endl;//无符号数运算,10-32算术结果-32,相当于-32加上2的32次方,结果4294967264
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;//int 整型间的运算32
std::cout << i - i2 << std::endl;//同上-32
std::cout << i - u << std::endl;//无符号和有符号数的运算,为0
std::cout << u - i << std::endl;//同上0
Exercise 2.4: Write a program to check whether your predictions were
correct. If not, study this section until you understand what the problem is.
#include<iostream>
int main(){
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;\
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
return 0;
}
Exercise 2.5: Determine the type of each of the following literals. Explain the differences among the literals in each of the four examples:
(a) ‘a’, L’a’, “a”, L"a"
字符字面值char
宽字符字面值wchar_t
字符串字面值string
宽字符串字面值
(b) 10, 10u, 10L, 10uL, 012, 0xC
整型十进制int,
无符号十进制整型unsigned int,
十进制整型long,
十进制无符号整型usigned long,
八进制整型
十六进制整型
© 3.14, 3.14f, 3.14L
浮点数double
浮点数float
浮点数long double
(d) 10, 10u, 10., 10e-2
十进制整型 int
无符号整型 usigned int
浮点数double
浮点数double
Exercise 2.6: What, if any, are the differences between the following
definitions:
int month = 9, day = 7;
int month = 09, day = 07;
第一行为十进制,第二行0开头为八进制字面值,出现9会报错。
Exercise 2.7: What values do these literals represent? What type does each have?
(a) “Who goes with F\145rgus?\012”
Who goes with Fergus?字符串string
(b) 3.14e1L
31.4 long double
(c ) 1024f
float
(d) 3.14L
3.14long double
Exercise 2.8: Using escape sequences, write a program to print 2 M followed by a newline. Modify the program to print 2, then a tab, then an M, followed by a newline.
#include <iostream>
int main()
{
std::cout << "2\115\012";
std::cout << "2\t\115\012";
return 0;
}
Exercise 2.9: Explain the following definitions. For those that are illegal, explain what’s wrong and how to correct it.
(a) std::cin >> int input_value;
错误
(b) int i = { 3.14 };
列表初始化,会丢失精度,错误
© double salary = wage = 9999.99;
错误
(d) int i = 3.14;
正确但会丢失精度
Exercise 2.10: What are the initial values, if any, of each of the following variables?
std::string global_str;//空字符串
int global_int;//全局变量 0
int main()
{
int local_int;//为赋值
std::string local_str;//空字符串
}
Exercise 2.11: Explain whether each of the following is a declaration or a
definition:
a) extern int ix = 1024;
定义
b) int iy;
定义
c) extern int iz
声明
Exercise 2.12: Which, if any, of the following names are invalid?
(a) int double = 3.14;
非法,double是关键字
(b) int _;
合法
© int catch-22;
非法
(d) int 1_or_2 = 1;
非法,只能以下划线或者字母开头
(e) double Double = 3.14;
合法
Exercise 2.13: What is the value of j in the following program?
int i = 42;
int main()
{
int i = 100;
int j = i;
}
j=100
Exercise 2.14: Is the following program legal? If so, what values are printed?
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
sum += i;
std::cout << i << " " << sum << std::endl;
100 45
Exercise 2.15: Which of the following definitions, if any, are invalid? Why?
(a) int ival = 1.01;
合法,但会丢失精度
(b) int &rval1 = 1.01;
不合法,不能定义字面值引用
© int &rval2 = ival;
合法
(d) int &rval3;
不合法,引用必须初始化
Exercise 2.16: Which, if any, of the following assignments are invalid? If they are valid, explain what they do.
int i = 0, &r1 = i; double d = 0, &r2 = d;
(a) r2 = 3.14159;
合法,对d赋值 d的值变为3.14159
(b) r2 = r1;
合法,将i的值赋给d d的值为0
© i = r2;
合法,将d的值赋给i,可能丢失精度
(d) r1 = d;
合法
Exercise 2.17: What does the following code print?
int i, &ri = i;
i = 5; ri = 10;
std::cout << i << " " << ri << std::endl;
10 10
Exercise 2.18: Write code to change the value of a pointer. Write code to
change the value to which the pointer points.
略
Exercise 2.19: Explain the key differences between pointers and references.
引用只是变量的别名,本身不是对象,必须初始化,初始化后不能改变绑定的对象。
指针本身是对象,能对本身赋值,可以不初始化,并且可以改变指向的对象。
Exercise 2.20: What does the following program do?
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1;
计算i*i并将值赋给i
Exercise 2.21: Explain each of the following definitions. Indicate whether any are illegal and, if so, why.
int i = 0;
(a) double* dp = &i;
不合法dp是指向double的指针,不能指向i
(b) int *ip = i;
不合法。不能将int 的值赋给指针(int 的值为0也不可以)
© int *p = &i;
合法p是指向i的指针
Exercise 2.22: Assuming p is a pointer to int, explain the following code:
if (p ) // ….p是空指针是为false 否则为true
if (*p) // …p所指向的对象为0是为false ,否则为true
Exercise 2.23: Given a pointer p, can you determine whether p points to a
valid object? If so, how? If not, why not?
不能知道
Exercise 2.24: Why is the initialization of p legal but that of lp illegal?
int i = 42; void p = &i; long lp = &i;
p是void*指针,可以指向任意对象
lp是指向long的指针,不能指向i
Exercise 2.25: Determine the types and values of each of the following variables.
(a) int* ip, i,&r = i;
ip指向int 的指针,i是int型,r是i的引用
(b) int i, ip = 0;
i是int 整型,ip是空指针
© int ip, ip2;
ip是指向int的指针,ip2不是int整型
Exercise 2.26: Which of the following are legal? For those that are illegal,
explain why.
(a) const int buf;
不合法 const要初始化
(b) int cnt = 0;
合法
© const int sz = cnt;
合法
(d) ++cnt; ++sz;
前者合法后者不合法,const的值不能改变
Exercise 2.27: Which of the following initializations are legal? Explain why.
(a) int i = -1, &r = 0;
i合法,r不合法,不能对字面值引用
(b) int *const p2 = &i2;
合法p2是指向i2的常量指针
© const int i = -1, &r = 0;
合法r是常量的引用
(d) const int *const p3 = &i2;
合法
(e) const int *p1 = &i2;
合法
(f) const int &const r2;
不合法
(g) const int i2 = i, &r = i;
合法
Exercise 2.28: Explain the following definitions. Identify any that are illegal.
(a) int i, *const cp;
i是int整型,合法;cp是指向整型的常量指针,常量必须初始化,不合法。
(b) int *p1, *const p2;
p1是指向int的指针,合法;p2是指向int的常量指针,必须初始化,不合法
© const int ic, &r = ic;
不合法。同上。
(d) const int *const p3;
不合法
(e) const int *p;
合法
Exercise 2.29: Uing the variables in the previous exercise, which of the following assignments are legal? Explain why.
(a) i = ic;
合法,ic是顶层const
(b) p1 = p3;
不合法,p3是底层const
© p1 = & ic;
不合法,ic是const int,p1指向int
(d) p3 = & ic;
不合法,p3是常量指针
(e) p2 = p1;
不合法,p2是常量指针
(f) ic = *p3;
不合法,ic的值不能被改变
Exercise 2.30: For each of the following declarations indicate whether the object being declared has top-level or low-level const.
const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
v2顶层const
p2底层const
p3既是顶层const也是底层const
Exercise 2.31: Given the declarations in the previous exercise determine whether the following assignments are legal. Explain how the top-level or low-level const applies in each case.
r1 = v2;合法
p1 = p2;不合法,p2是底层const
p2 = p1;合法
p1 = p3; 不合法
p2 = p3;合法
Exercise 2.32: Is the following code legal or not? If not, how might you make it legal?
int null = 0, *p = null;
不合法,改为
*p=nullptr;
Exercise 2.33: Using the variable definitions from this section, determine what happens in each of these assignments:
int i = 0, &r = i;
auto a = r; // a is an int (r is an alias for i, which has type int)
const int ci = i, &cr = ci;
auto b = ci; // b is an int (top-level const in ci is dropped)
auto c = cr; // c is an int (cr is an alias for ci whose const is top-level)
auto d = &i; // d is an int*(& of an int object is int*)
auto e = &ci; // e is const int*(& of a const object is low-level const)
const auto f = ci; // deduced type of ci is int; f has type const int
auto &g = ci; // g is a const int& that is bound to ci
a = 42; b = 42; c = 42;
d = 42; e = 42; g = 42;
abc合法,
d是int*,不合法
f是常量,不合法
g是常量引用,不合法
Exercise 2.34: Write a program containing the variables and assignments from the previous exercise. Print the variables before and after the assignments to check whether your predictions in the previous exercise were correct. If not, study the examples until you can convince yourself you know what led you to the wrong conclusion.
略
Exercise 2.35: Determine the types deduced in each of the following
definitions. Once you’ve figured out the types, write a program to see
whether you were correct.
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;
Exercise 2.36: In the following code, determine the type of each variable
and the value each variable has when the code finishes:
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
Exercise 2.37: Assignment is an example of an expression that yields a
reference type. The type is a reference to the type of the left-hand operand.
That is, if i is an int, then the type of the expression i = x is int&. Using
that knowledge, determine the type and value of each variable in this code:
int a = 3, b = 4;
decltype(a) c = a;
decltype(a = b) d = a;
Exercise 2.38: Describe the differences in type deduction between
decltype and auto. Give an example of an expression where auto and
decltype will deduce the same type and an example where they will deduce
differing types.
Exercise 2.39: Compile the following program to see what happens when
you forget the semicolon after a class definition. Remember the message for
future reference.
struct Foo { /* empty */ } // Note: no semicolon
int main()
{
return 0;
}
Exercise 2.40: Write your own version of the Sales_data class.
Exercise 2.41: Use your Sales_data class to rewrite the exercises in §
1.5.1 (p. 22), § 1.5.2 (p. 24), and § 1.6 (p. 25). For now, you should define
your Sales_data class in the same file as your main function.
Exercise 2.42: Write your own version of the Sales_data.h header and
use it to rewrite the exercise from § 2.6.2 (p. 76).