Lab 0
- 代码用现代 C++ 的风格进行编写,基本思想是每个对象都被设计为具有尽可能小的公共接口。具有大量的内部检查,并且知道如何自我清理,避免操作的配对。(如:malloc/free、new/delete 等)还有很多现代 C++ 风格的建议,比如不要使用 malloc/free、new/delete;不要使用普通指针,要使用智能指针(仅在必要时使用);避免模板、线程、锁和虚函数等;避免 C 语言的字符串,用 C++ 提供的字符串 std::string;不要使用 C 风格的强制转换,必要的话采用 C++ 静态强制转换 static_cast;更喜欢通过常量引用传递函数参数,将变量和方法设置为常量;避免使用全局变量,对每个变量赋予最小范围;遵循 RAII(Resource Acquisition Is Initialization)原则,即资源的获取与初始化绑定,资源的释放与对象的销毁绑定。
- C++ 中类的声明和函数实现一般是分开的,类的声明一般在 XXX.h 中,其中只有极少数简单的函数会直接实现,大部分函数都在 XXX.cpp 中。在.cpp 中需要包含.h 文件即 include "XXX.h"即可。其中<>主要包含标准库或系统级头文件,编译器只会在预定的系统目录中查找头文件。" "则主要包含自定义的头文件,编译器会首先在当前源文件所在目录查找,随后在用户包含路径中查找,最后在系统目录中查找。两种的区别便于区分是自定义还是标准库中的函数。
- 在 cpp 中的函数实现方式为返回类型 类名::函数名(参数列表){函数实现}。这里的::为作用域解析运算符,即告诉编辑器这里实现的函数名是哪个类的。
- 拓展:std 命名空间。C++ 的标准库(Standard Library)中的所有组件(string 类、cout 对象、vector 容器等)都被封装在一个名为std 的命名空间。命名空间主要用于避免名称冲突,通过使用 std::string 才能明确引用标准库的字符串类。两种不需要每次都是用 std::的方法(极其不推荐,每次都是用 std::是最标准的方法):使用 using namespace std;(注:此写法常见于竞赛场景),该方法会把 std 中的所有组件命名导入,但会污染该头文件的全局命名空间;使用 using std::string;只引入 string 这个命名,较为安全。
- 在 64 位系统上,long 和 long long 没区别,unsigned long 和 unsigned long long 没区别。long long 和 unsigned long long 都是 C++11 引入的,追求最高移植性使用这两个;在系统编程中通常使用 unsigned long(32 位系统为 unsigned int)表示内存地址、大小或与系统 API 交互(size_t 为其别名)。
- 类成员一般_类成员名或者 m_类成员名,表示其作为类成员,且权限为 private 或者 protect。
- const 成员函数,在成员函数参数列表之后,具体实现{}之间可以加 const 关键词,表示该函数是一个'只读'函数,不会修改对象的任何非静态数据成员。对于编译器而言,他会将 this 指针修改为常量指针,即不允许你修改非静态数据。
- C++ 类型的 string 或者 C 类型的 char*都是以'\0'结尾,C 类型强制以这个结尾,C++ 为了和 C 兼容也有这个规定,但可以直接使用其内部成员函数更方便。
类成员初始化: (1)类内初始化器,在类成员的定义中后跟{},表示该类型数据初始化为零值(类类型则为默认构造函数)。如 size_t _buffer_read{};和 std::vector _buffer{}; (2)构造函数初始化列表。在类的构造函数参数列表后跟:成员函数名(初始化值),...,成员函数名(初始化值){构造函数实现;} 例子如下:
ByteStream::ByteStream(const size_t capacity) :_buffer(capacity), _capacity(capacity), _buffer_remain(capacity) {}
(3)构造函数内部赋值。这就不多说了。 (4)需要注意的是常量(const 修饰),只能被初始化不能被赋值,1,2 都属于初始化,(静态常量例外,即可以在类内使用赋值语句赋初值)3 属于赋值语句。 (5)构造优先级,会先采取 1 即类内初始化器,后采取 2 初始化列表,最后采取构造函数内部赋值。
Lab 2
Optional 容器
简单介绍
一个将值本身和是否有值的状态包装在一起的容器。
在以上代码中将 isn 用 optional 容器存储,并且 ackno 的返回类型也为 optional。如下所示:
std::optional<WrappingInt32> _isn{}; //记录 isn std::optional<WrappingInt32> ackno() const;
当想要访问内部值时需先检查是否有值再访问,如下所示:


