加密笔记1
C++枚举类详解
1. 枚举类的定义
在C++11新标准中引入了枚举类(Enum Class),也称为强类型枚举。枚举类的定义格式如下:
1 | enum class 枚举类型名: 底层类型 {枚举值列表}; |
- 默认底层类型:如果未指定底层类型,默认为
int类型。 - 自定义底层类型:可以指定其他整数类型,如
char,以节省空间。
示例:
1 | enum class Type { General, Light, Medium, Heavy}; // 所有枚举常量都是int类型 |
2. 枚举类的优势
- 强作用域:枚举类的使用范围仅限于定义它的代码块,避免了传统枚举可能引起的作用域污染。
- 转换限制:枚举类对象不能与整型隐式转换,这有助于避免许多由于类型混淆而导致的错误。
- 可自定义底层类型:可以指定枚举类的底层类型为
char等其他整数类型,以节省内存空间。
示例:
1 | enum class Color { |
3. 枚举类的使用
- 声明和定义:枚举类的声明需要使用
enum class关键字,后面跟随枚举类的名字和一对花括号,花括号内定义枚举成员。 - 访问枚举成员:枚举类作用域内定义的变量,其值只能通过枚举类进行类型限定访问。
示例:
1 | enum class Side { Left, Right }; |
4. 枚举类的位运算
当枚举值需要通过位运算进行组合时,可以为枚举类定义位运算符(如|和&)。由于枚举类不支持隐式转换,因此需要显式转换。
示例:
1 | enum class Printer_flags { |
5. 枚举类的应用场景
- 函数参数或返回值:用于指示函数的状态或执行的结果。
- 类的成员变量:用于表示对象的状态或属性。
- 条件语句:在
if、switch等条件语句中作为条件表达式,以根据枚举值执行不同的代码路径。 - 循环:在循环中作为迭代器的值,尽管这种情况较少见,但在某些特定场景下可能会用到。
示例:
1 | void f(Traffic_light x) { |
6. 枚举类与整数的转换
- 显式转换:可以将整型值显式转换为枚举类型,但转换结果是未定义的,除非整型值在枚举类型的底层类型范围内。
- 隐式转换:枚举类对象不能隐式转换为整型。
示例:
1 | enum class Warning { green, yellow, orange, red }; |
总结
C++枚举类(Enum Class)是C++11引入的一种强类型枚举,提供了更强的类型安全性和作用域限制。通过使用枚举类,可以避免传统枚举的一些问题,如作用域污染和隐式类型转换。枚举类不仅限于与枚举类内部定义的数据进行对比,还可以用于各种需要这些枚举值的场景,如函数参数、类成员变量、条件语句和循环等。此外,通过定义位运算符,可以方便地对枚举值进行组合操作。
静态转换与动态转换
静态转换(Static Cast)
静态转换是将一种数据类型的值强制转换为另一种数据类型的值。
静态转换通常用于比较类型相似的对象之间的转换,例如将 int 类型转换为 float 类型。
静态转换不进行任何运行时类型检查,因此可能会导致运行时错误。
1 | int i = 10; |
动态转换(Dynamic Cast)
动态转换通常用于将一个基类指针或引用转换为派生类指针或引用。动态转换在运行时进行类型检查,如果不能进行转换则返回空指针或引发异常。
1 | class Base {}; |
C++ 中的类型限定符
类型限定符提供了变量的额外信息,用于在定义变量或函数时改变它们的默认行为的关键字。
| 限定符 | 含义 |
|---|---|
| const | const 定义常量,表示该变量的值不能被修改。 |
| volatile | 修饰符 volatile 告诉该变量的值可能会被程序以外的因素改变,如硬件或其他线程。 |
| restrict | 由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 |
| mutable | mutable 用于修饰类的成员变量。被 mutable 修饰的成员变量可以被修改,即使它们所在的对象是 const 的。 |
| static | 用于定义静态变量,表示该变量的作用域仅限于当前文件或当前函数内,不会被其他文件或函数访问。 |
| register | 用于定义寄存器变量,表示该变量被频繁使用,可以存储在CPU的寄存器中,以提高程序的运行效率。 |
C++ 引用 vs 指针
引用很容易与指针混淆,它们之间有三个主要的不同:
不存在空引用。引用必须连接到一块合法的内存。
一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
引用必须在创建时被初始化。指针可以在任何时间被初始化。
虚函数
C++虚函数是如何调用子类重写函数的
在C++中,虚函数是实现运行时多态的关键机制。通过使用virtual关键字声明虚函数,子类可以重写这些方法,而无需在父类中实现它们。当创建指向子类的父类指针并调用其虚函数时,实际上是在调用子类中的重写函数,而非父类中的函数。以下是详细的调用过程和相关机制:
- 虚函数声明:
- 在父类中使用
virtual关键字声明函数,使其成为虚函数。例如:
- 在父类中使用
1 | class Human { |
- 子类重写:
- 子类可以重写父类的虚函数。为了确保正确重写,可以使用
override关键字。例如:
- 子类可以重写父类的虚函数。为了确保正确重写,可以使用
1 | class Man : public Human { |
- 动态绑定:
- 当通过父类指针调用虚函数时,实际调用的是子类中重写的函数。这称为动态绑定(Dynamic Dispatch)。例如:
1 | int main() { |
虚函数表(vTable):
- 每个包含虚函数的类都有一个对应的虚函数表(vTable),其中存储了该类所有虚函数的地址。
- 每个类对象都有一个指向其对应vTable的指针(vptr)。
- 当对象被创建时,vptr被初始化为指向该类的vTable。
虚函数调用过程:
- 当通过父类指针调用虚函数时,编译器会生成代码来访问对象的vptr。
- 通过vptr找到对应的vTable,然后根据vTable中的地址调用实际的函数。
- 如果子类重写了虚函数,vTable中的地址会被更新为子类函数的地址。
析构函数:
- 为了确保正确清理资源,建议将析构函数也声明为虚函数。例如:
1 | class Human { |
- 纯虚函数:
- 纯虚函数是在基类中声明但未实现的虚函数,其声明以
= 0结尾。例如:
- 纯虚函数是在基类中声明但未实现的虚函数,其声明以
1 | class Animal { |
- 包含纯虚函数的类称为抽象类,不能被实例化。
- override关键字:
override关键字用于标记派生类的成员函数,表明其覆盖了基类的虚函数。这有助于提高代码的可读性和编译器检查。例如:
1 | class Man : public Human { |
总结
虚函数通过动态绑定机制实现了运行时多态性。通过在父类中声明虚函数并在子类中重写,可以灵活地控制类的行为。虚函数表(vTable)和虚函数指针(vptr)是实现动态绑定的关键结构。正确使用虚函数可以提高代码的可读性和可扩展性。
| 关键点 | 描述 |
|---|---|
| 虚函数声明 | 使用virtual关键字声明 |
| 子类重写 | 子类使用相同的函数签名重写虚函数 |
| 动态绑定 | 通过父类指针调用虚函数时,实际调用子类重写的函数 |
| 虚函数表(vTable) | 存储虚函数地址的表 |
| 虚函数指针(vptr) | 指向vTable的指针 |
| 析构函数 | 建议声明为虚函数以确保正确清理资源 |
| 纯虚函数 | 声明为= 0的虚函数,使类成为抽象类 |
| override关键字 | 标记覆盖基类虚函数,提高代码可读性和编译检查 |




