一、typedef
typedef是C/C++语言中保留的关键字,用来定义一种数据类型的别名。
ypedef定义的类型的作用域只在该语句的作用域之内
typedef经常使用的场景包括以下几种:
- 指定一个简单的别名,避免了书写过长的类型名称
- 实现一种定长的类型,在跨平台编程的时候尤其重要
- 使用一种方便阅读的单词来作为别名,方便阅读代码
1.1 减少书写类型的长度
这一使用方式比较常见的就是在C语言中定义结构体,在C语言中定义结构体的方式如下:(包含3种)
///第一种方式
struct MyStruct {
int data1;
char data2;
};
//之后定义变量
struct MyStruct a, b;
///第二种方式(声明的同时定义)
struct MyStruct {
int data1;
char data2;
}a, b;
///第三种方式(不需要提供结构体名字,直接定义)
struct {
int data1;
char data2;
}a, b;
为了简化书写,可以使用typedef来简化(这种方式在Windows API中非常的常见,使用过Win32 API编程的读者应该深有体会),比如Windows定义四边形区域RECT结构的代码:
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
使用typedef之后,可以将上面的代码修改为:
///第一种情况
struct MyStruct {
int data1;
char data2;
};
typedef struct MyStruct newtype;
newtype a, b;
///第二种情况
typedef struct MyStruct {
int data1;
char data2;
} newtype;
newtype a, b;
///第三种情况
typedef struct {
int data1;
char data2;
} newtype;
newtype a, b;
需要注意的是上面描述的是C语言的使用方法,在C++中定义struct之后再次声明变量时,不需要使用struct关键字。
1.2 实现一种定长的类型
在C/C++中并没有规定int类型的长度,因此在不同的机器上很有可能表示int类型变量所占用的字节数是不同的,这样有时候会带来一些问题。为了解决这些问题,很多时候可以定义一个固定大小的类型(比如32位的Int类型)Int32,用来表示固定长度的整型。这样在任意的机器上都可以使用这个Int32的类型,保证它的长度是固定的32位(至于它底层使用的真正类型,会根据具体机器上使用对应的类型),在OpenGL中就采用了这种方式,定义了许多固定大小的整型。
1.3 实现一种有意义可读的别名
例如下面这段代码,速度和分数都是使用int类型来表示,函数调用的时候传入的也是整型,把速度变量传入到原本接收成绩的参数,并不会有错误。
int current_speed ;
int high_score ;
void congratulate(int your_score) {
if (your_score > high_score)
...
}
为了区别开这两种类型(只是从阅读代码者角度来看,对编译器来说二者并无不同),可以使用typedef来定义两个不同的别名:
typedef int km_per_hour ;
typedef int points ;
km_per_hour current_speed ;
points high_score ;
void congratulate(points your_score) {
if (your_score > high_score)
...
}
这样代码阅读起来更加清晰一些。
另外需要注意的是:当使用typedef定义了points(km_per_hour)为int类型,在使用int类型定义的时候都可以使用这两个别名来替换,但并不是二者可以完全替换,当定义unsigned int等类型时,使用points(km_per_hour)替换int是错误的。
unsigned int a; // Okay
unsigned km_per_hour b; // 编译报错
long int c; // Okay
long km_per_hour d; // 编译报错
二、C++11下新的选择(使用using定义别名)
C++11 中扩展了using的使用场景(C++11之前using主要用来引入命名空间名字 如:using namespace std;),可以使用using定义类型的别名:
使用语法如下:
using 别名 = xxx(类型);
通过语法可以看出,using声明别名的顺序和typedef是正好相反:typedef首先是类型,接着是别名,而using使用别名作为左侧的参数,之后才是右侧的类型,例如上面的类型定义:
typedef int points;
using points = int; //等价的写法
在定义诸如函数指针等类型时,使用using的方式更加自然和易读:
typedef void (*FP) (int, const std::string&);
using FP = void (*) (int, const std::string&); //等价的using别名
另外using可以在模板别名中使用,但是typedef不可以:
template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;
// usage
Vec<int> vec;
若使用typedef的方式改写如下:
template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;
// usage
Vec<int> vec;
当你使用编译器编译的时候,将会得到类似:error: a typedef cannot be a template的错误信息。
那么,为什么typedef不可以呢?在 n1449 中提到过这样的话:”we specifically avoid the term “typedef template” and introduce the new syntax involving the pair “using” and “=” to help avoid confusion: we are not defining any types here, we are introducing a synonym (i.e. alias) for an abstraction of a type-id (i.e. type expression) involving template parameters.” 所以,我认为这其实是标准委员会他们的观点与选择,在C++11中,也是完全鼓励用using,而不用typedef的。
那么,如果我们想要用typedef做到这一点,应该怎么办呢?如Meyers所述以及一些STL的做法,那就是包装一层,如:
template <typename T>
struct Vec
{
typedef MyVector<T, MyAlloc<T>> type;
};
// usage
Vec<int>::type vec;
正如你所看到的,这样是非常不漂亮的。而更糟糕的是,如果你想要把这样的类型用在模板类或者进行参数传递的时候,你需要使用typename强制指定这样的成员为类型,而不是说这样的::type是一个静态成员亦或者其它情况可以满足这样的语法,如:
template <typename T>
class Widget
{
typename Vec<T>::type vec;
};
然而,如果是使用using语法的模板别名,你则完全避免了因为::type引起的问题,也就完全不需要typename来指定了。
template <typename T>
class Widget
{
Vec<T> vec;
};
都会非常的自然,所以于此,非常推荐using,而非typedef。
归根到底就是一句话,在C++11中,请使用using,而非typedef
————————————————
原文链接:https://blog.csdn.net/csxiaoshui/article/details/78038799