C++/C++11中用于定义类型别名的两种方法:typedef和using

本文深入探讨了C++中类型别名的概念,介绍了typedef和using两种定义类型别名的方法,对比了它们之间的语法和语义差异,以及在模板中的应用。通过实例展示了如何简化复杂类型名称,提高代码可读性和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++/C++11中用于定义类型别名的两种方法:typedef和using

 

类型别名(type alias)是一个名字,它是某种类型的同义词。使用类型别名有很多好处,它让复杂的类型名字变得简单明了、易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的。在C++中,任何有效类型都可以有别名。

有两种方法可用于定义类型别名:传统的方法是使用关键字typedef;C++11中规定了一种新的方法,使用别名声明(alias declaration)来定义类型的别名,即使用using.

关键字typedef作为声明语句中的基本数据类型的一部分出现。含有typedef的声明语句定义的不再是变量而是类型别名。和以前的声明语句一样,这里的声明符也可以包含类型修饰,从而也能由基本数据类型构造出复合类型来。

C++11中用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名。

类型别名和类型的名字等价,只要是类型的名字能出现的地方,就能使用类型别名

如果某个类型别名指代的是复合类型或常量,那么把它用到声明语句里就会产生意想不到的后果。

使用typedef定义的别名和使用using定义的别名在语义上是等效的。 唯一的区别是typedef在模板中有一定的局限性,而using没有。

尽管typedef具有更长的历史记录并且在现有代码中可能更常见,但using更通用。

无论是typedef还是using,它们都不会创建新的数据类型,它们仅仅创建现有类型的同义词(synonyms)。不能用于更改现有类型名称的含义。

typedef和using标识符可以声明数组和函数类型,指针和引用,类类型等等。但不能与任何其它标识符组合使用。仅在它们可见的范围内有效:不同的函数或类声明可以定义具有不同含义的相同名字的类型。

typedef的用法包括:定义一种类型的别名;用于struct声明;用来定义与平台无关的类型;用于回调函数;为复杂的声明定义一个新的简单的别名。

typedef是定义了一种类型的新别名,不同于宏,并不是简单的字符串替换。当const和typedef一起出现时,typedef不是简单的字符串替换:

注意:typedef int* INT; const INT p;相当于int* const p;而不是const int* p;

在使用typedef时,不能在声明中有多个存储类关键字:ypedef就像auto,extern, mutable, static, register一样,是一个存储类关键字。即typedef中不能出现这些关键字。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

typedef.cpp内容如下:

 
  1. #include "typedef.hpp"

  2. #include <iostream>

  3. #include <vector>

  4. #include <string>

  5. #include <ios>

  6. #include <type_traits>

  7. #include <typeinfo>

  8.  
  9. namespace typedef_ {

  10.  
  11. ///////////////////////////////////////////////

  12. // reference: https://en.cppreference.com/w/cpp/language/typedef

  13.  
  14. // std::add_const, like many other metafunctions, use member typedefs

  15. template< class T>

  16. struct add_const {

  17. typedef const T type;

  18. };

  19.  
  20. int test_typedef_1()

  21. {

  22. // simple typedef

  23. typedef unsigned long ulong;

  24.  
  25. // the following two objects have the same type

  26. unsigned long l1;

  27. ulong l2;

  28.  
  29. // more complicated typedef

  30. typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10];

  31.  
  32. // the following two objects have the same type

  33. int a1[10];

  34. arr_t a2;

  35. for (int i = 0; i < 10; ++i)

  36. a2[i] = i;

  37. for (int i = 0; i < 10; ++i)

  38. fprintf(stdout, "a2 value: %d\n", a2[i]);

  39.  
  40. // common C idiom to avoid having to write "struct S"

  41. typedef struct {int a; int b;} S, *pS;

  42.  
  43. // the following two objects have the same type

  44. pS ps1;

  45. S* ps2;

  46.  
  47. // error: storage-class-specifier cannot appear in a typedef declaration

  48. // typedef static unsigned int uint;

  49.  
  50. // typedef can be used anywhere in the decl-specifier-seq

  51. long unsigned typedef int long ullong;

  52. // more conventionally spelled "typedef unsigned long long int ullong;"

  53.  
  54. // std::add_const, like many other metafunctions, use member typedefs

  55. /*template< class T>

  56. struct add_const { // error: a template declaration cannot appear at block scope

  57. typedef const T type;

  58. };*/

  59.  
  60. typedef struct Node {

  61. //struct listNode* next; // declares a new (incomplete) struct type named listNode

  62. } listNode; // error: conflicts with the previously declared struct name

  63.  
  64. struct Node2 {

  65. int data;

  66. struct Node2* nextptr;

  67. };

  68.  
  69. // 使用typedef可以将上面的Node2改写为:

  70. typedef struct Node3 Node3;

  71. struct Node3 {

  72. int data;

  73. Node3* nextptr;

  74. };

  75.  
  76. typedef double wages; // wages是double的同义词

  77. typedef wages base, *p; // base是double的同义词,p是double*的同义词

  78.  
  79. return 0;

  80. }

  81.  
  82. ////////////////////////////////////////////

  83. // reference: http://www.cplusplus.com/doc/tutorial/other_data_types/

  84. int test_typedef_2()

  85. {

  86. // In C++, there are two syntaxes for creating such type aliases:

  87. // The first, inherited from the C language, uses the typedef keyword:

  88. // typedef existing_type new_type_name;

  89. {

  90. typedef char C;

  91. typedef unsigned int WORD;

  92. typedef char * pChar;

  93. typedef char field [50];

  94.  
  95. C mychar, anotherchar, *ptc1;

  96. WORD myword;

  97. pChar ptc2;

  98. field name;

  99. }

  100.  
  101. // a second syntax to define type aliases was introduced in the C++ language:

  102. // using new_type_name = existing_type;

  103. {

  104. //the same type aliases as above could be defined as:

  105. using C = char;

  106. using WORD = unsigned int;

  107. using pChar = char *;

  108. using field = char [50];

  109. }

  110.  
  111. {

  112. // 注意: typedef int* INT; const INT p;相当于int* const p;而不是const int* p;

  113. typedef int* INT;

  114. int a[] = {1, 2, 3};

  115. const INT p1 = &a[0];

  116. const int* p2 = &a[0];

  117. //++p1; // error: increment of read-only variable 'p1'

  118. p1[0] = -100;

  119. fprintf(stdout, "a[0]: %d\n", a[0]);

  120. ++p2;

  121. //p2[0] = -200; // error: assignment of read-only location '*p2'

  122. }

  123.  
  124. return 0;

  125. }

  126.  
  127. ////////////////////////////////////////////////////

  128. // reference: https://msdn.microsoft.com/en-us/library/dn467695.aspx

  129. void actual_function(int arg) { fprintf(stdout, "value: %d\n", arg); }

  130. template<typename T>

  131. using ptr2 = T*;

  132.  
  133. template<typename T>

  134. struct MyAlloc {

  135. typedef T value_type;

  136.  
  137. MyAlloc() { }

  138. template<typename U>

  139. MyAlloc(const MyAlloc<U>&) { }

  140.  
  141. bool operator == (const MyAlloc&) const { return true; }

  142. bool operator != (const MyAlloc&) const { return false; }

  143.  
  144. T* allocate(const size_t n) const {

  145. fprintf(stdout, "start allocate\n");

  146. if (n == 0) {

  147. return nullptr;

  148. }

  149.  
  150. if (n > static_cast<size_t>(-1) / sizeof(T)) {

  151. throw std::bad_array_new_length();

  152. }

  153.  
  154. void* const pv = malloc(n * sizeof(T));

  155.  
  156. if (!pv) {

  157. throw std::bad_alloc();

  158. }

  159.  
  160. return static_cast<T*>(pv);

  161. }

  162.  
  163. void deallocate(T* const p, size_t) const {

  164. fprintf(stdout, "start deallocate\n");

  165. free(p);

  166. }

  167. };

  168.  
  169. using MyIntVector = std::vector<int, MyAlloc<int>>;

  170.  
  171. int test_typedef_3()

  172. {

  173.  
  174. { // An alias does not introduce a new type and cannot change the meaning of an existing type name

  175. // C++11

  176. using counter = long;

  177.  
  178. // C++03 equivalent:

  179. // typedef long counter;

  180. }

  181.  
  182. { // Aliases also work with function pointers

  183. // C++11

  184. using func = void(*)(int);

  185.  
  186. // C++03 equivalent:

  187. // typedef void (*func)(int);

  188.  
  189. // func can be assigned to a function pointer value

  190. func fptr = &actual_function;

  191. fptr(10);

  192. }

  193.  
  194. { // A limitation of the typedef mechanism is that it doesn't work with templates. However, the type alias syntax in C++11 enables the creation of alias templates:

  195. //template<typename T> using ptr = T*; // error: a template declaration cannot appear at block scope

  196.  
  197. // the name 'ptr<T>' is now an alias for pointer to T

  198. ptr2<int> ptr_int;

  199. }

  200.  
  201. { // an alias template with a custom allocator

  202. MyIntVector foov = { 1701, 1764, 1664 };

  203. for (auto a: foov)

  204. fprintf(stdout, " %d ", a);

  205. fprintf(stdout, "\n");

  206. }

  207.  
  208. return 0;

  209. }

  210.  
  211. ///////////////////////////////////////////////////////

  212. // reference: https://zh.wikipedia.org/zh-hk/Typedef

  213. int do_math(float arg1, int arg2) { return arg2; }

  214.  
  215. int call_a_func(int (*call_this)(float, int))

  216. {

  217. int output = call_this(5.5, 7);

  218. return output;

  219. }

  220.  
  221. // 将上面改为使用typedef,回调函数

  222. typedef int (*MathFunc)(float, int);

  223. int call_a_func2(MathFunc call_this)

  224. {

  225. int output = call_this(5.5, 7);

  226. return output;

  227. }

  228.  
  229. int test_typedef_4()

  230. {

  231. int final_result = call_a_func(&do_math);

  232. fprintf(stdout, "final_result: %d\n", final_result);

  233.  
  234. int final_result2 = call_a_func2(&do_math);

  235. fprintf(stdout, "final_result2: %d\n", final_result2);

  236.  
  237. return 0;

  238. }

  239.  
  240. ////////////////////////////////////////////

  241. // reference: https://en.cppreference.com/w/cpp/language/type_alias

  242. // type alias, identical to

  243. // typedef std::ios_base::fmtflags flags;

  244. using flags = std::ios_base::fmtflags;

  245. // the name 'flags' now denotes a type:

  246. flags fl = std::ios_base::dec;

  247.  
  248. // type alias, identical to

  249. // typedef void (*func)(int, int);

  250. using func = void (*) (int, int);

  251. // the name 'func' now denotes a pointer to function:

  252. void example(int, int) {}

  253. func f = example;

  254.  
  255. // alias template

  256. template<class T>

  257. using ptr = T*;

  258. // the name 'ptr<T>' is now an alias for pointer to T

  259. ptr<int> x;

  260.  
  261. // type alias used to hide a template parameter

  262. template<class CharT>

  263. using mystring = std::basic_string<CharT, std::char_traits<CharT>>;

  264. mystring<char> str;

  265.  
  266. // type alias can introduce a member typedef name

  267. template<typename T>

  268. struct Container { using value_type = T; };

  269. // which can be used in generic programming

  270. template<typename Container>

  271. void g(const Container& c)

  272. {

  273. typename Container::value_type n;

  274. fprintf(stdout, "type: %s\n", typeid(n).name());

  275. }

  276.  
  277. // type alias used to simplify the syntax of std::enable_if

  278. template<typename T>

  279. using Invoke = typename T::type;

  280. template<typename Condition>

  281. using EnableIf = Invoke<std::enable_if<Condition::value>>;

  282. template<typename T, typename = EnableIf<std::is_polymorphic<T>>>

  283. int fpoly_only(T t) { return 1; }

  284.  
  285. struct S { virtual ~S() {} };

  286.  
  287. int test_typedef_5()

  288. {

  289. Container<int> c;

  290. g(c); // Container::value_type will be int in this function

  291. //fpoly_only(c); // error: enable_if prohibits this

  292. S s;

  293. fpoly_only(s); // okay: enable_if allows this

  294.  
  295. return 0;

  296. }

  297.  
  298. } // namespace typedef_

  299.  

CMakeLists.txt内容如下:

 
  1. PROJECT(CppBaseTest)

  2. CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

  3.  
  4. # 支持C++11

  5. SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2 -std=c11")

  6. SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2 -std=c++11")

  7. # 支持C++14, when gcc version > 5.1, use -std=c++14 instead of c++1y

  8. SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2 -std=c++1y")

  9.  
  10. MESSAGE(STATUS "project source dir: ${PROJECT_SOURCE_DIR}")

  11. SET(PATH_SRC_FILES ${PROJECT_SOURCE_DIR}/./../../demo/CppBaseTest)

  12. MESSAGE(STATUS "path src files: ${PATH_SRC_FILES}")

  13.  
  14. # 指定头文件的搜索路径

  15. INCLUDE_DIRECTORIES(${PATH_SRC_FILES})

  16.  
  17. # 递归查询所有匹配的文件:*.cpp

  18. FILE(GLOB_RECURSE CPP_LIST ${PATH_SRC_FILES}/*.cpp)

  19. FILE(GLOB_RECURSE C_LIST ${PATH_SRC_FILES}/*.c)

  20. #MESSAGE(STATUS "cpp list: ${C_LIST}")

  21.  
  22. # 编译可执行程序

  23. ADD_EXECUTABLE(CppBaseTest ${CPP_LIST} ${C_LIST})

  24. # 用来为target添加需要链接的共享库,指定工程所用的依赖库,包括动态库和静态库

  25. TARGET_LINK_LIBRARIES(CppBaseTest pthread)

build.sh脚本内容如下:

 
  1. #! /bin/bash

  2.  
  3. real_path=$(realpath $0)

  4. dir_name=`dirname "${real_path}"`

  5. echo "real_path: ${real_path}, dir_name: ${dir_name}"

  6.  
  7. new_dir_name=${dir_name}/build

  8. mkdir -p ${new_dir_name}

  9. cd ${new_dir_name}

  10. cmake ..

  11. make

  12.  
  13. cd -

编译及测试方法如下:首先执行build.sh,然后再执行./build/CppBaseTest即可。

GitHub: https://github.com/fengbingchun/Messy_Test  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值