面向过程的一些基础
流
理解>> 和<<运算符的本质
cin>>a; cin是istream类的一个对象,从流中读取一段,并赋值给后方
cin当做条件时,当流中没有数据 代表条件为假(istream类的对象都可这么用)
同理cout也是ostream类的一个对象,对象就是object,按照这样理解比较方便
这本书里的对象意思是具某种类型的一段内存空间
变量
基本内置类型

几个注意点:
- 最好使用double,因为float和double的运算时间差不多,但是double的精度还更大
- 一个int至少和一个short一样大、一个long至少和一个int一样大、一个long long至少和一个long一样大
- 因为short通常太小,而long一般和int一样大,所以,若超过了int的尺寸,就用long long
字面值常量
转义序列

指定字面值的类型

true和false是布尔类型字面值常量
nullptr是指针类型字面值常量
变量
辨析声明 定义 初始化 赋值
| 名词 | 含义 | 辨析 |
|---|---|---|
| 声明 | 在内存中开辟一块空间 int a; | 和定义类似 |
| 定义 | 在内存中开辟一块空间 int a; | 和声明类似 |
| 初始化 | 创建变量时就赋予给他一个初始值 int a=1; 在开辟空间的时候顺便给他了一个值 | |
| 赋值 | 把当前变量的值擦除,写入新的值 a=3; 擦除存储空间的那个值,重新给了他一个值 |
声明使得名字被程序所知,变量可以被声明很多次,但是不能被定义很多次
external int a; 就是声明a
当原本的变量定义为全局变量时,才可以在声明处,使用这个变量的定义
定义在块状区域内的变量,即使他和块状区域外面某个变量重名,但是,还是以块状区域内定义的为标准,要访问块状区域外边的变量时使用作用域解析符
当然,大块状区域的有效范围高于大块状之内的小块状的有效范围
初始化
默认初始化
定义变量的时候没有给他一个值
就是声明和定义

对于类的对象创建时的初始化问题,有的类要求对象显示初始化,有的不要求初始化
string 类没有初始化时,默认值是0
初始化的方式
推广使用列表初始化
就是{ } 这样
基本内置类型不适合列表初始化
变量的名称规范
- 标识符由数字、字母、下划线组成。必须以字母或者下划线开头
- 标识符不可用内置的标识符,且不能连续出现两个下划线
- 不能以下划线紧连大写字母开头
- 定义在函数体外的标识符不能以下划线开头
- 变量名称不能是C++关键字
C++ 关键字

复合类型
组成:基本数据类型+声明符
平时的int a; a就是变量名列表,同样属于声明符
引用
cpp
int a=3;
int &b=a;
通常说的是左值引用,相当于给变量起了另一个名称,他并不是对象
因此,引用定义时必须初始化,只能绑定在对象上,不能绑定在字面值或者计算结果上
引用可以指向指针,这是阅读声明从右往左读很轻松的
指针
指针本身就是一个对象,他里边存放着另一个对象的内存地址(因此指针的值就是他指向对象的内存空间的地址)
指针只能指向对象,因此他不能指向引用(引用没有地址)
void* 类型指针
这个类型的指针能容纳一切地址,但是无法知道地址那里的数据是什么类型(即不能使用解引用符号来探查他指向内存空间的值)
指向指针的指针
可以让一个指针指向另一个指针,只需让声明符使用两次就行
cpp
int a=1; int *b=&a; int **c=&b;
const限定符
作用:为了限定某个对象的值,防止其他人无意之间修改
const对象必须初始化
默认状态下,const对象仅在文件内有效,编译器会在编译的过程中把用到该变量的地方换为相对应的值
当多个文件中定义了同名const时,相当与在多个文件中定义了独立的变量
共享const的方法:
当出现一个const变量(只有初始值不是常量的时候才这么做,是常量的时候直接extern就行),初始值不是常量表达式,但是又要在文件间共享,需要在每个文件中使用extern const int a=func();
const的引用
常量指针:指针本身是一个常量(因为指针是一个对象).
cpp
int a=1;
int *const p=&a; //同样从右往左看,p是个常量,他的类型是指针,所以他只是常量那么简单
const int *p=&a; //p是个指针,是个对象,前面const限定了他指向的东西不能通过他来改变(没有规定不能从其他突进改变)


顶层const和底层const的对比
就指针类型来说
| 哪一层const | 指向的对象是否可变 | 可否通过自己来改变指向对象的值 | |
|---|---|---|---|
| const int *p=&a; | 底层const | 可以 | 不可以 |
| int * const p=&a; | 顶层const | 不可以(因为这个指针是常量) | 看情况 |
constexpr
可以显示的将变量声明为constexpr来告诉编译器表达式是常量
constexpr int mf=20;
如果你认为一个变量是常量表达式,就将他声明为constexpr
auto
auto一般会忽略顶层const,保留底层const
一般在auto前显示加const保留顶层const
decltype
cpp
decltype (fun/name) var ;
decltype 顶层和顶层const都会识别
推断含有const的变量时,定义的变量必须赋值
decltype(( i )) x; x类型为int & 双层括号的结果必为引用
字符串 向量和数组
名称空间
cpp
namespace abc {
//在里边定义各种内容即可
}
头文件不应该包含using声明,因为,如果 某个头文件如果包含了这个头文件,可能发生不经意间的名字冲突错误
string类库
初始化方式

操作

is指的是输入流对象,像cin什么的
空string连\0也没有
判定库

适合处理string中的每一个字符,使用给予范围的for循环处理更方便
for(auto &c:str){
}
使用引用,可以直接修改字符串中的值
vector 类库
初始化

方法

迭代器
和指针唯一区别就是获取地址不需要取值运算符,其余操作完全一样
数组
- 定义数组的时候要制定好类型,不能用auto关键词推断类型
- 不允许拷贝赋值
- 理解的时候得按照从内向外阅读
- 默认的情况下,类型修饰符从右向左依次绑定
声明的解读:
cpp
int (*point)[10]=&arr;
point是一个指针,指向一个含有10个元素的数组,数组元素的类型是int
标准库函数 begin() 和end() 直接获取数组的首指针和尾后指针
用数组初始化vector
vector name (begin(arry),end(arry));
类型转换
- 当赋值给无符号数一个超过他表示的类型的数的时候,结果是无符号数的总数—超过他范围的那个数
- 当从无符号数中减去一个值的时候,不管这个数是不是无符号数,我们都应该确保最后的结果不是一个负数
- 赋值给无符号数一个超过他表示范围的值的时候,结果是初始值对无符号类型表示数值总数取模后的余数
隐式转换
c++ 先将两种类型的值统一类型后再进行值的相加
发生隐式类型转换的情形

image-20200724231805378
其他隐式转换情形:
- 数组名自动转换为数组首部元素的指针
显式转换
有时不得不用强制类型转换,但是这样做是非常危险的
命名的强制类型转换:
通用格式:
cpp
cast-name<type>(value);
cast-name是强制转换的类型
type是要转换的类型
value是需要转换的值
以下是几种cast_name
static_cast
适用于将大类型转换为小类型,比如double转换为float,此时编译器不会发出警告信息
对于编译器无法自动执行的类型转换也很有用(比如找回void* 中指针的值)
cpp
int a=3;
void *b=&a;
auto voidp=static_cast<int *>(b);
cout<<*voidp;
const_cast
只能改变运算对象的底层const(即可以用底层const给非顶层const赋值)
cpp
const int *c=&a;
int *temp= const_cast<int *>(c);
cout<<*temp;
*temp=2;
cout<<*temp;
这时就可以用temp指针改变a的值
reinterpret_cast
通常为运算对象的位模式提高比较底层上的重新解释
p145
最后,应该避免强制类型转换
表达式
基础
表达式是有一个或者多个运算对象组成,对表达式求值将得到一个结果
字面值和变量是最简单的表达式
表达式加个分号就是语句
左值和右值
当一个对象被用作右值时,用的是对象的值(内容),当对象被用作左值时,用到的是他的对象的身份(在内存中的位置)

位运算符
检查和设置二进制位
书本138页,现在觉得没啥用,以后用到再总结
运算符优先级


函数
参数
命名规范
任意两个形参都不能同名,而且函数最外层作用域中的局部变量也不能使用与函数形参一样的名字
参数传递
引用传递
如果函数无需改变引用形参的值,将他声明为常量引用
按值传递
因为拷贝大的对象或容器的时候比较低效,甚至有的对象根本不支持拷贝操作
如果函数无需改变引用形参的值,最好声明为常量引用
const形参和实参
p192
传递数组
通常传递首指针和尾后指针
含有可变形参的函数
这其实就是一个模板传递同种类型的参数,和vector类似,只是不能修改该对象中的值
调用的时候,参数列表必须在{ } 内使用
局部对象
名字具有作用域,对象拥有生命周期
局部变量的生命周期依赖于定义的方式
局部静态对象:生命周期存在于整个程序运行过程
返回值
- 与初始化变量的方式一样,返回的值用于初始化调用点的一个临时量
- 若函数返回一个引用,则该引用仅是他所引用对象的一个别名
不要返回局部对象的指针或者引用 因为这样做不安全,在函数体执行完毕后,引用的东西可能会被释放
调用一个返回引用的函数得到左值,其他的返回类型都是右值
可以返回一个列表,但是必须用{ } 方式返回,返回值类型是vector就可以
返回一个数组
使用
cpp
auto fun(int i)->int(*)[10]; //返回一个指向十个整形元素的指针这种声明方式可以更好理解函数返回值类型
函数重载
顶层const和没有顶层const 的形参区分不开
重载情形:
重载那些非常相似的操作
重载的选择:
对于那种参数个数相同,且类型可以相互转换的情形

函数匹配用到再看吧,现在看了估计也用不出来
p219
函数指针
函数指针指向的是函数
函数名就是函数的地址 (取值运算符可有可无)
函数类型就是去掉函数名的那一部分
函数指针不用解引用就能访问函数
用decltype推断函数时,返回的函数类型,不是指向函数的指针,要用指针,加上*即可

