- 第I部分:C++基础(2–7章)
- 第II部分:C++标准库(8-12章)
- 第III部分:面向对象设计(13–16章)
第二章 变量和基本类型
2.1 基本内置类型
2.1.1 算术类型
-
整型:int bool char
-
浮点型:float double
-
C++11: long long
内置类型的及其实现: 可寻址的最小内存块:字节(byte)大多数8bit 存储的基本单元:字 (word) 由几个字节组成 32或64个byte 每个字节与一个数字关联起来:地址(address)
带符号类型和无符号类型
char、signed char和unsigned char, char由(不同机器的)编译器决定是否有符号。所以不要用char进行算术运算。
练习:2.1
2.1.2 类型转换
编译器会根据环境自动类型转换
- 非bool->bool: 0为false, 非0为true;
- bool->非bool: false=0, true=1;
- 浮点数->integral: 保留整数部分;
- 超出unsigned类型:高位丢失,也就是与所能表示的最大数+1的求余结果
- 超出signed类型:结果是未定义的。可能崩溃。
负数补码:除了符号位,其他位取反+1
含有unsigned类型的表达式
unsigned u = 10; int i = -42;
cout << u + i;//会将int转化为unsigned, 结果是4294967264
//切记不要混用unsigned与signed
2.1.3 字面值常量
科学计数法:5e-6 = 5 x 10^-6
2.2 变量
2.2.1 变量定义
初始化不是赋值,初始化含义:创建变量是赋予其一个初始值,而赋值时把对象当前的值擦除,用新值代替.
C++11:列表初始化
值初始化:有括号
int i = 0;
int i = {0};
int i(0);
int i{0};
int i = int(10);//创建临时变量然后初始化i
默认初始化
int i;
int *i = new int;//无括号
2.2.2 变量声明和定义的关系
extern int i;//声明未定义
int j;//声明定义
//显式初始化
extern double pi = 3.14//定义
在函数内部初始化一个extern变量,会报错;
变量只能被定义一次,但可以多次声明。
只有定义了的变量才能赋值。
2.2.4 名字的作用域
C++中大多数作用域以{ }分隔,全局作用域::后接variable name.
2.3 复合类型
声明语句:base type + declarator(声明符)列表
2.3.1 引用
即左值引用。
-
无法重新绑定引用,引用必须被初始化;(因为一旦初始化引用,会与初始值的对象bind在一起)
-
不能定义引用的引用,可以定义引用的指针。(因为引用本身不是一个对象,只是已存在对象的别名)
-
除了引用P55和P534外,引用的类型必须与绑定的对象严格匹配。
2.3.2 指针
- 指针可以赋值和拷贝;(指针本身是一个对象)
- 无需再定义是赋初值;
- 不能定义指向引用的指针:int& *p;(因为引用不是对象,没有实际地址)
- 除了引用P56和P534外,pointer的类型必须与指向的对象严格匹配。
指针的值(地址)
- 指向一个对象;
- 指向紧邻对象所占空间的下一个位置;(数组的下标访问)
- 空指针:nullptr、0和NULL;(不指向任何对象)
- 无效指针,以上都不是(野指针)
建议初始化所有指针
如果使用未初始化的指针:
1.可能访问一个不存在的地址;
2.如果指针所占空间有内容,而这些内容又被当作地址,难以判断是否legal.
void*指针
用于存放任意对象的地址。
不能直接操作void*指针所指的对象,因为不知道这个对象到底是什么类型,也就无法确定能执行哪些操作。
2.3.3 理解复合类型的声明
指向指针的引用
int i = 42;
int *p;
int *&r = p; //r是一个对指针p的引用
r = &i;//给r赋值&i就是令p指向i
*r = 0;//解引用r得到i
要理解r的类型,应该从右往左读。
2.4 const限定符
because once after created a const object, it’s value can’t be changed, const object must be initialize.
const int i = get_size();//运行时初始化
const int j = 42; //编译时初始化
const int k; //error:k是一个未初始化的常量
初始化和const
主要限制就是只能在const类型的对象上执行不改变其内容的操作。
2.4.1 const的引用
初始化和const的引用
引用类型必须与其所引用对象的类型一致,第一种例外就是:在初始化常量时允许用任意表达式作为初始值,只要表达式的结果能转换成引用的类型即可。
int i = 42;
const int &r1 = i;//&i与&r1相同
const int &r2 = 42;//正确
const int &r3 = r1 * 2;//正确 &r3与&r1不同
int &r4 = r1 * 2;//error.r4是一个普通非常量引用
double dval = 3.14;
const int &ri = dval;//就是ri和dval的地址是不同的。
//为了确保ri bind一个int,编译器会将上诉代码转换
const int temp = dval;//临时int变量
const int &ri = temp;//让ri bind这个临时量
如果ri不是常量时,允许对ri赋值,这样改变的时临时变量,而不是dval,那么引用就没有意义了,所以这种情况是非法的。
对const的引用可能引用一个并非const的对象
常量引用只是对引用可参与的操作做出了限定,对于引用的对象本身是不是常量未作限定。因为对象也可能是非常量,所以允许通过其他方式改变它的值。
2.4.2 指针和const
point to const
指向常量的指针:不能用于改变其所指对象的值。
const double pi = 3.14;//pi是常量
double *ptr = π//error.ptr是一个普通pointer
const double *cptr = π//正确
*cptr = 42;//error.不能给*cptr赋值
指针的类型必须与其所指的对象必须是一个常量,但是有两个例外
第一种就是允许令一个指向常量的指针指向一个非常量对象:
double dval = 3.14;
cptr = &dval;//正确,但不能通过cptr修改dval
const pointer
常量指针:必须初始化,一旦初始化完成,它的值就不能再改变,像引用一样。
int errNumb = 0;
int *const curErr = &errNumb;//curErr将一直指向errNumb
2.4.3 顶层const
top-level const:指针本身是一个常量
low-level const:指针所指的对象是一个常量。
区别:
在执行对象的拷贝时:top-level const 执行拷贝操作拷入和拷出的对象是否是常量都没什么影响;
low-level const 执行对象拷贝,拷入和拷出的对象必须具有相同的底层const资格或者两个对象的数据类型必须能够转换,一般来说,非常量可以转化为常量。
练习:
2.30:Follwing sentences, please explain the object is top-level const or low-level const?
const int v2 = 0; //top
int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = & v2, *const p3 = &i, &r2 = v2;//p2-low p3-top r2-low
2.31: 对于上一个练习,下列语句是否合法?
r1 = v2;//legal. 拷贝赋值实际修改v1的值。
p1 = p2;//illegal. p1是normal pointer,p2是low-level const,这样可能会错误的改变常量的值。
p2 = p1;//legal. p2可以指向非常量,但不能通过p2更改它所指的值
p1 = p3;//illegal. p3包含low-level const
p2 = p3;//legal. p2和p3包含相同的底层const
2.4.4 constexpr和常量表达式
常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。
字面值属于常量表达式,用常量表达式初始化const对象也是常量表达式。
const int max_files = 20;//yes
const int limit = max_files + 1;//yes
int staff_size = 27;//no 非const
const int sz = get_size();//no 直到运行时才能获取到具体值。
constexpr变量
必须用常量表达式初始化:
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr innt sz = size();//只有当size是一个constexpr函数时,才正确。
指针和constexpr
限定符constexpr仅对有效,与指针所指的对象无关:
const int *p = nullptr;//p is point to const
constexpr int *q = nullptr;//q is const point
constexpr 既可以指向常量也可以指向非常量。
int j = 0;
constexpr int i = 42;
//i和j必须定义在函数体外,因为
constexpr const int *p = &i;//p是常量指针常量,指向int常量i,不可修改指向和指向的值
constexpr int *p1 = &j;//p1是常量指针,指向integer j
2.5 处理类型
2.5.1 类型别名
类型别名是某种类型的同义词。使复杂的类型名字变得更简单。
-
typedef
typedef double wages; typedef wages base, *p;//p是double*的同义词
-
using
using SI = Sales_item;//SI是Sales_Item的同义词。
2.5.2 auto类型说明符
auto声明的类型必须有初始值,声明多个变量,则所有变量的初始基本数据类型必须一样。
auto i = 0, *p = &i; //right. i是整数,p是int*
auto sz = 0, pi = 3.14;//error. sz与pi类型不一致
-
当引用作为出世之时,参与初始化的其实是引用对象的值。
int i = 0, &r = i; auto a = r;//a是一个整数
-
auto会忽略top-level const , 同时low-level const 会被保留。
const int ci = i, &cr = ci; auto b = ci;//b是int(顶层const被忽略) auto c = cr;//c是int(cr是ci的别名,ci本身是一个顶层const) auto d = &i;//d是一个整型指针(整数的地址就是指向证书的指针) auto e = &ci;//e是一个point to const int 的指针(对常量对象取地址是一个底层const)
-
如果希望推断出auto类型是一个顶层const, 需要明确指出
const auto f = ci;//f是const int
-
引用的类型设为auto
auto &g = ci;//g是整型常量引用 auto &h = 42;//error: 不能为非常量引用bind字面值 const auto &j = 42;//可以为常量引用绑定字面值
-
auto引用,初始值的顶层常量属性被保留
auto k = ci, &l = i;//k是int l是int& auto &m = ci, *p = &ci;//m是cosnt int &, p是const int * auto &n = i, *p2 = &ci;//error. i的类型是int而&ci的类型是const int
2.5.3 decltype 类型指示符
为了满足从表达式推断出要定义的变量的类型,但是不想使用表达式的值初始化变量。
编译器只会分析表达式结果的类型,并不计算值。
decltype(f()) sum = x;//sum的类型就是函数f的返回类型,不会调用函数,
decltype处理变量,则decltype返回该变量的类型(包括顶层const和引用在内)
const int ci = 0, &cj = ci;
decltype(ci) x = 0;//x是const int
decltype(cj) y = x;//y是const int&, y bind x
decltype(cj) z;//error. z是const int&, 必须初始化
decltype 和引用
有些表达式将返回一个引用:
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;//未初始化的 int 而decltye(r)是一个引用
decltype(*p) c;//error. c是int&, 必须初始化
decltype((i)) d;//error,d是int& 必须初始化
结论:decltype返回表达式结果对应的类型,r+0的结果是int;
解引用操作,decltype将得到引用类型;
如果表达式是加了括号的变量,结果是引用。
2.6 自定义数据结构
2.6.3 编写自己的头文件
预处理器概述
头文件保护符
#ifndef xxx
#define xxx
#include <iostream>
...
#endif
第三章 字符串、向量和数组
3.2 string
可变长的字符序列。string包含在namespace std中。
#include <string>
using std::string;
3.2.2 string对象的操作
string的操作 | 含义 |
---|---|
os << s | 将s写到输出流os当中,返回os |
is>>s | 从is中读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从is中读取一行赋给s,返回is |
s. empty () | s为空返回true,否则返回false |
s.size () | 返回s 中字符的个数 |
s [n] | 返回s中第n个字符的引用,位置n从0计起 |
sl+s2 | 返回s1和s2连接后的结果 |
s1=s2 | 用s2的副本代替s1中原来的字符 |
s1==s2 s1!=s2 | 如果s1和s2中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感 |
<,<=, >,>= | 利用字符在字典中的顺序进行比较,且对字母的大小写敏感 |
第六章 函数
6.5.2 constexpr 函数
约定:
- 函数的返回类型即所有形参都是字面值类型;
- 函数体中只有return 语句。
6.7 函数指针
第十二章 动态内存
12.1 动态内存与智能指针
12.1.1 shared_ptr 类
shared
虚继承:
[https://www.cnblogs.com/weekbo/p/8384943.html]