基本数据类型
算术类型,void
为了支持分离式编译,C++语言将声明和定义区分开来。声明(declaration)使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。而定义(definition)负责创建与名字关联的实体。
变量声明规定了变量的类型和名字,在这一点上定义与之相同。但是除此之外,定义还申请存储空间,也可能会为变量赋一个初始值。
变量声明
extern int i; //声明
int j; //声明并定义
extern double pi = 3.14; //定义如前所述,变量的定义包括一个基本数据类型(base type)和一组声明符。在同一条定义语句中,虽然基本数据类型只有一个,但是声明符的形式却可以不同。也就是说,一条定义语句可能定义出不同类型的变量
int i = 1024, *p = &i, &r = i;const默认internal linkage,可以添加extern变成external linkage
常引用
double dval = 3.14
const int& r = dval;
//等价于
const int temp = dval;
const int& r = temp;左值引用不允许绑定表达式。因为从上述等价表示可以看出建立的引用没有改变真正字面上看上去绑定对象(这里是dval)的能力。
const expression
一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定
使用constexpr修饰可以要求检查是不是常量表达式
auto
一般忽略顶层const。对于auto引用,初始值中的顶层常量属性仍然保留。
const int ci = 1;
auto &m = ci, *p = &ci; //const int&, const int*要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。
int ia[][];
for (auto row : ia)
for (auto col : row)//💥auto会将row退化成指针运算对象的求值顺序与优先级和结合律无关
隐式类型转换
- 条件(语境?)中向bool转换 这里涉及到一个平时没思考的问题。标准保证了尽管cin向bool的转换是explicit的,某些语境下仍然可以自动隐式转换为bool
- 算术运算
- 初始化和赋值,函数调用
- 数组向指针,
void*, nullptr, 底层const - 类类型定义的转换
显式转换
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
如不在乎精度损失的算术类型转换,将void*转回具体指针类型
const_cast常常用于有函数重载的上下文中
C++语言中的大多数语句都以分号结束,一个表达式末尾加上分号就变成了表达式语句(expression statement)。表达式语句的作用是执行表达式并丢弃掉求值结果
名字的作用域是程序文本的一部分,名字在其中可见
对象的生命周期是程序执行过程中该对象存在的一段时间
顶层const可以表示任意对象是常量
const int ci = 42;底层const只会在指针和引用的语境下出现。
当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换,即非常量可以转换成常量,反之则不行
函数的返回类型决定函数调用是否是左值。调用一个返回引用的函数得到左值,其他返回类型得到右值。
合成的默认构造函数 默认初始化
名称查找规则
friend只影响权限,不能作为声明
iostream是stringstream和fstream的基类
std::unitbuf可以将一个流设置为每次写都flush,std::nounitbuf恢复为默认策略
当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。标准库将cout和cin关联在一起
tie
每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream。
除array外,swap不对任何元素进行拷贝、删除或插入操作,因此可以保证在常数时间内完成
除string外,swap不会使迭代器失效,只是指向新容器
默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数我们希望以引用方式传递,或是要绑定参数的类型无法拷贝。
可以使用ref,构造一个对象,包含引用,可以拷贝
不能
explicit构造函数只能用于直接初始化
std::shared_ptr<int> ptr = new int;