重要知识点
-
浮点运算选用double,因为float通常精度不够,而且双精度浮点和单精度浮点的计算代价相差无几。
-
给无符号类型赋予一个超出表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。
-
给有符号类型赋予一个超出表示范围的值时,结果是未定义的。
-
表达式里既有带符号类型又有无符号类型,带符号类型会自动转换为无符号类型。
-
字符串字面值的实际长度比它的内容多1,因为字符串是字符数组,编译器会在字符串的结尾处添加一个空字符
'\0'。 -
对象是具有某种数据类型的内存空间。
-
定义变量时没有指定初值,则变量被默认初始化:
- 定义在函数体之外的变量被初始化为0;
- 定义在函数体之内的内置类型不被初始化,其值是未定义的;
- 类对象如果没有初始化,其值由类决定;
-
任何包含显式初始化的声明即成为定义:
extern int i; // 声明 extern int i = 0; // 定义 int i; // 声明并定义 -
全局作用域本身没有名字,可以使用
::获取全局变量(::var)。 -
引用: 引用(
refers to)另外一种类型。-
引用不是对象,是一个已经存在对象的别名;(所以不能定义引用的引用)
-
引用必须初始化;
-
引用和它的初始值对象绑定在一起,无法重新绑定到另外一个对象;
指针是一个对象,因此可以定义对指针的引用
int *p; int *&r = p; // 对指针p的引用
指针: 指向(
point to)另外一种类型。-
指针是一个对象,且可以指向不同的对象;
-
指针无须在定义时初始化;
-
和内置类型一样,在块级作用域内定义的指针如果没有初始化,其值也是不确定的;
-
指针的类型要和它指向的对象严格匹配;
-
void*是一种特殊的指针类型,可用于存放任意对象的地址;引用不是对象,没有实际地址,因此不能定义指向引用的指针;
-
-
复合类型:
// 引用和指针都是复合类型, 其中 // int 是基本数据类型 // *和& 是类型修饰符 // a和b 是声明符 int *a = 0; int &b = a; -
const限定符-
const对象必须初始化; -
const对象仅在文件内有效,多个文件中出现同名const对象时,等同于在不同文件中分别定义了独立变量; -
如果想在多个文件中共享
const对象,必须在变量声明和定义之前添加extern关键字; -
const引用: 指向常量的引用-
允许使用任意表达式作为初始值,只要表达式的值可以转换为引用的类型即可;
-
指向常量的引用并不要求所指的对象必须是一个常量,而仅仅只要求不能通过引用改变所指对象的值;
int i = 42; const int &r1 = i; // ok, 因为整形可以转换为整形常量 const int &r2 = i * 2; // ok, 表达式 i * 2的结果是整形,整形可以转换为整形常量 int &r3 = r1 * 2; // not ok, r1*2结果为整形常量,整形常量无法转换为整形, 需要添加const限定符 const int &r4 = r1 * 2; //ok r4 = 24; // not ok, 不能通过引用改变所指对象的值
-
-
指向常量的指针
-
指向常量的指针并不要求所指的对象必须是一个常量,而仅仅只要求不能通过指针改变所指对象的值;
const double pi = 3.14; double *ptr = π // not ok const double *ptr = π // ok, ptr是指向常量的指针 *ptr = 3.14159 // not ok, 不能通过指针改变所指对象的值 double e = 2.7 const double *p = &e; // ok
-
-
常量指针
-
指针是一个对象,
const对象必须初始化,因此常量指针(const pointer)必须初始化; -
常量指针(
*const)说明指针本身是一个常量,指针所指对象的内存地址不能再改变,但所指(非常量)对象的值是可以变的;int i = 1; int *const pi = &i; // pi是一个常量指针,所指对象是一个整形对象 const int j = 2; const int *const pj = &j; // pj 是一个常量指针,所指对象是一个整形常量 *pi = 2; // ok pi = &j; // not ok *pj = 1; // not ok pj = &i; // not ok
-
-
常量表达式
constexpr-
指的是值不会改变,且在编译过程中就能得到计算结果的表达式;
-
字面值属于常量表达式;
字面值类型:算术类型(整型、字符型、布尔型、浮点型)、引用和指针都属于字面值类型
整型和浮点型字面值: 1 1.0
字符和字符串字面值:'a' "a"
布尔型和指针字面值:true nullptr
转义序列:\n \t \r ...
-
用常量表达式初始化的
const对象也是常量表达式;const int i = 1; // ok const int j = i + i; // ok const int &r = 3; // ok, 常量引用可以绑定字面值 int k = 2; // not ok -
将变量声明为
constexpr类型时,编译器会验证变量的值是否是一个常量表达式;声明为constexpr的变量一定是一个常量;constexpr int i = 1; // 1是常量表达式 constexpr int j = i +1; // i+1是常量表达式 constexpr int k = size(); // 需要编译器验证size()的值是否是常量表达式,只有当size()是一个constexpr函数时才是正确的声明语句 -
constexpr声明中如果定义了一个指针,限定符constexpr仅针对指针有效,与指针所指对象无关;constexpr int *np = nullptr; // np是一个指向整型的常量指针,其值为空 int i = 1; // i 是一个整型 constexpr int j = 1; // j 是一个整形常量 constexpr const int *pj = &j; // pj是一个指向整型常量的常量指针 constexpr int *pi = &i; // pi是一个指向整型的常量指针
-
-
-
类型处理
-
类型别名
-
typedeftypedef int integer; // integer 是 int的同义词 typedef float number, *numberptr; // number 是float的同义词,numberptr是float*的同义词 -
usingusing SI = Sales_item; //SI是Sales_item的同义词 -
当类型别名是一个指针型别名时,不能错误地把类型别名替换成原来的样子进行理解
typedef char *charptr; const charptr p = 0; // p是一个指向char的常量指针 const charptr *p; // p是一个指针,所指对象是一个指向char的常量指针 // charptr替换为原来的样子 const char *p = 0; // charptr基本类型是一个指针,替换后基本类型是char,p变成了一个指向常量char的指针
-
-
auto:类型说明符,编译器自动分析表达式类型auto 会忽略掉顶层
const, 如果希望保留顶层const,则需要明确指出(主动添加const):int i = 1; const int ci = i, &ri = ci; //ci 是一个整型常量,ri是对整型常量的引用 auto a = ci; // a 是整型 const auto ca = ci; // ca是整型常量 auto b = ri; // b 是整型,ri是对ci的引用 auto c = &i; // c 是整型指针 auto d = &ci; // d 是一个指向整型常量的指针 auto &e = ci, *p = &ci; // e是对整型常量的引用,p是指向整型常量的指针 auto &r1 = 1; // not ok, 不能为非常量引用绑定字面值 const auto &r2 = 2; // ok, 可以为常量引用绑定字面值 -
decltype:类型指示符,选择并返回操作数的类型编译器会分析表达式的类型,并不实际计算表达式的值
// 如果表达式的内容是一个变量,decltype返回变量的类型 const int ci = 1; &ri = ci; decltype(ci) a = 1; // a 是 const int decltype(ri) b = a; // b 是 const int& decltype(ri+0) c; // c 是const int // 如果给变量加上了一层或多层括号,编译器会把它当作表达式,从而得到引用类型 decltype((ci)) d = 2; // d 是 const int& // 如果表达式的内容是解引用,则decltype得到引用类型 int i = 1; *p = &i; &r = i; decltype(*p) e; // e 是 int&, 引用必须初始化 decltype(*p) f = i; // ok
参考书籍:《C++ Primer》第5版
-