%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% # 类型命名 C++中,可通过以下声明语句将一个"**名称**" 声明为**指代某一个类型**: - class declaration - union declaration - enum declaration - **类型别名声明** - typedef declaration:`typedef type-id identifier` - type alias declaration: `using identifier = type-id` <br> # 类型别名 C++中的 "类型别名" 提供了一种为**现有类型**定义**新名称**的方法。 C++中提供了两种方式来定义类型别名: - **`typedef` 声明**(typedef declaration):`typedef type-id identifier;` - **`using` 声明**(type alias declaration): `using identifier = type-id;` **类型别名的作用域**遵循 C++中的**通用作用域规则**,其**作用域取决于==类型别名声明的位置**==。 类型别名可以在**全局作用域**、**命名空间作用域**、**类作用域**、**函数作用域**内声明。 示例: ```cpp title:type_alias_exam.cpp typedef char Byte // 定义Byte为char类型的别名 using Integer = int; // 定义Integer为int类型的别名 using IntVector = std::vector<int> // 定义IntVector为`std::vector<int>`类型的别名 //using的优势在于能够很容易地定义模板别名 template<typename T> using MapOfString = std::map<std::string, T>; ``` > [!NOTE] 类型别名不具有 "链接性",其只是编译器解析类型时使用的一个别名,只在声明所在的翻译单元的编译期间有效。 > [!caution] 宏定义不属于类型别名! > > 预处理器指令 `#define` 定义的"**宏**" 只是让**预处理器 "单纯"地进行==名称"替换"**==,因此可能出现如下情况: > > ```cpp > #define FLOAT_POINTER float* > FLOAT_POINTER pa, pb; // 预处理器将该声明转换为 `float* pa, pb`; 使得 pb 是 float 变量而非指针 > ``` > > 而 `typedef` 设置类型别名则不会有上述问题: > > ```cpp > typedef char* byte_ptr; > byte_ptr a, b; // 等价于 char *a, *b; > ``` > > > [!caution] 类型别名前的 cv 限定符是对整个 "给定类型" 的修饰 > > 当使用一个类型别名时,如果前面存在 `const` 限定符,则 `const` 是对这整个 "**==给定类型==**" 的修饰。 > 如果该别名是一个 **"指针" 类型的别名**,则意味着声明了一个 "**常量指针**" 类型。 > > 如下所示: > > ```cpp > using pstring = char*; > // or typedef char* pstring; > > // const 是对"给定类型"的修饰 > // `pstring` 是一个指向 char 的"指针类型". > // 因此下一语句中的 `const` 是对"指针类型"的修饰, 表示"常量指针", 而不是对 `char` 的修饰. > const pstring cstr = nullptr; // cstr 是指向 char 的常量指针 (const pointer) > const pstring *ps; // ps 是一个指针, 该指针指向一个"指向 `char` 类型的常量指针". > ``` <br> ## `typedef` 声明 `typedef` 是 C 和早期 C++中定义类型别名的传统方式。 ```cpp title:typedef_exam.cpp // ------------------1.为"类型"声明别名 typedef std::vector<std::pair<std::string, int>> vec_str_i; // 'vec_str_i'是类型别名 // ------------------2.为 "函数类型" 声明别名 // 为一个函数类型声明别名 typedef bool Func1(const string&, const string&); // `Func1`是函数类型的类型别名 // 为lengthCompare函数的函数类型声明别名; 等价于上述语句 typedef decltype(lengthCompare) Func2; // ------------------3.为函数指针声明别名 // 为一个函数指针声明别名 typedef void (*FuncPtr)(const string&, const string&); // `FuncPtr`是函数指针的类型别名 // 为一个指向lengthCompare函数的函数类型的"函数指针"声明别名 typedef decltype(lengthCompare) *FuncPtr2; // `FuncPtr`是函数指针的类型别名 ``` 注意 `typedef` 声明静态数组别名时,数组大小放在最后: ```cpp typedef int int_array[4]; // `int_array` 是 `int[4]`类型的别名 int_array a; // a是一个含有4个int元素的数组类型 // 等价声明: using int_array = int[4]; ``` <br> ## `using` 声明 C++11 引入了 `using` 声明作为定义类型别名的现代替代方法。 ![[_attachment/02-开发笔记/01-cpp/类型相关/cpp-类型别名.assets/IMG-cpp-类型别名-D3FF31C3EDADC6ECE67C135360BD5741.png|453]] ```cpp ++ title:using_typealias_exam.cpp // --------------------1.使用using为"类型"声明别名 using vec_str_i = std::vector<std::pair<std::string, int>>; // 'vec_str_i'是类型别名 // --------------------2.使用using为一个"函数类型"声明别名 using F = int(int*, int); F func1(int); // --------------------3.使用using为一个"函数指针类型"声明别名 using PF = int(*)(int*, int); PF funcptr = &f; // 函数指针 using FuncType = decltype(foo); Functype* funcptr2 = &foo; // 函数指针 // --------------------4.使用using为一个"成员函数指针类型"声明别名 using FuncPtr = int (MyClass::*)(int*, int); using ConstFuncPtr = int (MyClass::*)(int*, int) const; FuncPtr = &MyClass::func; ConstFuncPtr = &Myclass::constFunc; ``` <br><br> ## `using` 和 `typedef` 的差异 `typedef` 只能用于为 "**已存在类型(type)**" 声明别名。 由于"模版"不是一个类型,因此 **`typedef` 无法为 "类模版" 定义一个别名**。 `using` 声明支持为 "**模版**" 声明 **==模版别名==**。 <br><br> # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # ♾️参考资料 # Footnotes