01
-
通常返回0表示好结果
-
后缀 .cc .cxx .cpp .cp .C
-
四个IO对象 cin cout cerr clog
-
#include <标准库头文件>
#include “自定义头文件” -
操纵符 endl 效果
结束当前行 并将于设备关联的缓冲区中的内容刷新到设备中
刷新缓冲器的操作可以保证将目前为止程序所产生的所有输出都真正写入到输入流中
而不仅仅是停留在内存中等待写入流 -
标准库定义的所有名字都在std的命名空间中
-
作用域运算符::
-
while(std::cin >> value)
表达式 std::cin >> value 的返回值是 std::cin
所以检查的是std::cin的状态
遇到文件结束符(CTRL+D(UNIX), CTRL+Z(WINDOWS))或者输入错误时 istream 对象的状态会变成假 -
后缀 .h .H .hpp .hxx
-
一般默认情况下 cin 会刷新 cout 程序非正常终止也会刷新 cout
cerr 默认是不缓冲的
clog 默认是缓冲的 -
在调试添加打印语句时 需要保证一直刷新流
否则程序崩溃 可能导致 输出可能停留在缓冲区中
从而导致关于程序崩溃位置的错误推断
02
-
基本数据类型
- 空类型
- 算术类型
- 浮点型
- 整型
- 整型数
- 字符
- 布尔值
-
各类型最小尺寸要求见
P30
-
一般来说 float 和 double 分别具有 7 和 16 个有效位
-
char是有符号还是无符号决定于编译器
-
赋给无符号一个超出范围表示的值 是对无符号表示的总数取模后的余数
#include <iostream> using namespace std; int main() { uint8_t v = -1; cout << int(v) << flush; return 0; } 输出是255 直接输出v是输出不了的 因为实际uint8_t是typedef unsigned char
-
赋给带符号一个超时范围表示的值 结果未定义
-
在一个表达式中 既有无符号数又有有符号数时 会自动将有符号的提升转换为无符号的 将会导致如上一点的不可预知行为
-
内置类型列表初始化时如果存在信息丢失的风险编译器将报错
int i{291.2}; error: narrowing conversion of '2.9119999999999999e+2' from 'double' to 'int' inside { } [-Wnarrowing]
-
extern 声明
-
初始化是创建时赋予初始值 赋值是擦除当前值赋予新值
-
初始化方式
int a = 0; int b = {0}; int c{0}; int d(0);
-
多行书写字符串字面值
cout << "hello " "world!" << endl;
-
默认初始化 以下针对 内置类型 内置类型 内置类型 进行说明 P40
如果内置类型未被显示初始化 其值由位置决定
定义于任何函数体之外的变量被初始化为0
定义于函数体内部的内置变量将不被初始化(静态局部变量例外 执行 值初始化
) -
自定义标识符
- 不能连续两个下划线
- 不能下划线紧连大写字
- 定义在函数体外的标识符不能以下划线开头
-
引用
引用类型与绑定对象类型需要严格匹配 两种例外 1 const 2 多态
- 引用只能绑定在对象上
- 引用本身不是一个对象 不能定义引用的引用
- 引用不能与字面值或者表达式的计算结果绑定在一起
-
指针的值
指针的类型与所指向的对象需要严格匹配 两种例外 1 const 2 多态
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置 比如尾指针
- 空指针 nullptr
- 无效指针 野指针
- 引用不是对象 所以无法定义指向引用的指针
-
指针都建议初始化 未初始化的指针或野指针会引发无法预料的后果
-
指针与引用区别 引用必须初始绑定 一旦绑定无法绑定到其他对象 而指针则无此限制
-
类型相同的
合法
指针 使用 == 或者 != 进行比较时 相等的几种情况- 都为空
- 指向同一对象
- 都指向统一对象的下一地址 比如尾指针
- 一个指针指向对象的下一个地址 另一个指针指向
另一个
对象
-
void*指针
- 比较
- 作为函数输入输出
- 赋值给另一个void*指针
- 不能直接操作void*指针指向的对象 因为不知道是啥
-
默认状态下 const 对象仅在文件内有效 详见P54 多个文件共享const可以使用 extern const
// test.cpp const int x = 1; const int *p1 = &x; //main.cpp #include <iostream> using namespace std; const int x = 2; const int *p2 = &x; int main() { cout << "hello world!" << endl; // 在这里打上断点 然后debug观察 p1 p2 *p1 *p2 就可以验证 }
-
对常量的引用称为常量引用(reference to const)
- 允许常量引用绑定 非常量 的对象 字面值 甚至是一个一般表达式
类似于ri绑定了一个临时变量
因为const是不允许改的 所以这样合法
如果去掉ri的const 那么改ri类似改一个临时变量 所以就把这种行为归为非法
double dval = 4.14; const int &ri = dval; // 相当于如下 const int temp = dval; const int &ri = temp;
- 允许常量引用绑定 非常量 的对象 字面值 甚至是一个一般表达式
-
指向常量的指针
(pointer to const) 指针常量
-
常量指针(const pointer)
指针本身是常量 -
顶层const
表示指针本身是常量 -
底层const
表示指向的对象是一个常量引用是指向性质的 常量引用是底层指针
-
将变量声明为 constexpr 可以由编译器来验证变量的值是否是一个常量表达式
-
常量表达式
- 不会改变
- 编译时期就可以得到计算结果的表达式
需要在运行时才可以计算得到 sz 的值 不是常量表达式 const int sz = getsize()
可以看出 使用constexpr的值必须编译时已知 但是cosnt的不需要
-
目前为止接触到的字面值类型
- 算术类型
- 引用
- 指针
-
constexpr修饰指针时 一定是修饰的指针本身而不是指针指向的对象
P59
constexpr指针的值受到严格限制 nullptr 或者 0 或者固定地址的对象
所有函数体之外定义的变量
静态局部对象
-
别名
typedef double wages;
wages 是 double 的别名typedef wages base, *p;
base 是 double 的别名 p 是 double* 的别名;using SI = Sales_Item;
SI 是 Sales_Item 的别名- typedef char *pstring;
- pstring 是一个指针
- pstring 是一个指向char的指针
- const pstring cstr;
- sctr 是一个常量pstring
- cstr 是一个常量([指向char的]指针)
- cstr 是一个常量指针
- const pstring *ps;
- 上面已经得到 const pstring 常量([指向char的]指针)
- ps 是一个指针 他的对象是指向char的常量指针
-
auto 自动推导类型
- auto 一般会忽略顶层const 底层const会保留P62
- 希望保留顶层const 需要显示 const auto
- auto x = 一个引用 auto对引用所绑定的对象进行推导
const int ci = 0; &cr = ci; auto b = cr; 其实是对ci进行推导 然后忽略顶层const 然后b是一个普通整型
-
decltype类型指示符 decltype需要参考左值右值相关内容
分析表达式得到他的类型 确不计算他的值 decltype(f()) sum = x;-
如果decltype使用的表达式是一个变量 则返回该变量的类型
(包括顶层const和引用在内 引用从来都作为其所指对象的同义词出现 只有在decltype这里例外了
) -
如果decltype使用的表达式不是一个变量 则返回表达式结果的类型
有些表达式向decltype返回一个引用
一般情况下意味着该表达式的结果对象能作为赋值语句的左值
-
如果decltype的是一个加了括号的变量 即如下
decltype(variable) 常规的
decltype((variable)) 这里的双层括号
那么其实decltype使用的表达式不是一个变量了 而是(variable)这样一个表达式
然后variable变量是一种可以作为赋值语句左值的特殊表达式
然后这是一个左值 然后这样的结果就会是一个引用类型
结论
decltype((variable))
的结果永远是引用
decltype(variable)
只有在variable本身是引用时结果才是引用int test_decltype() { int i = 42; int *p = &i; int &r = i; // 错误 a 是一个引用 未初始化报错 decltype(r) a; // 正确 表达式的结果是一个具体的int值 而非引用 decltype(r + 0) b; // 错误 *p解引用得到的对象是一个左值可以给这个结果赋值 类型是int& 未初始化报错 decltype(*p) c; // 错误 decltype((i)) d; // 正确 decltype(i) e; }
-
-
类内初始值 创建对象时 类内初始值用于初始化数据成员 没有类内初始值的将
默认初始化(内置类型就有可能未初始化出现错误哈哈哈)
可以用以下的几种初始化方式进行类内初始值的设置 除了用()的方式struct test_struct { int a = 2; int b{3}; int c = {4}; int d; };
-
预处理器
-
#define
-
#ifdef
-
#ifndef
-
#endif
-
#pragma once
-
预处理器 在C++编译过程中执行的一段程序
-
预处理器变量 由预处理器管理的变量(命名空间不在std中)
在程序编译之前预处理器负责将程序中的预处理器变量转换为真实值
-