C++ 中typedef的用法总结
前言
在总结中,比较简单的我只是做了简略的总结,对我来说比较难理解的做了重点的解析。
一、基本类型别名定义
1、简单类型别名
- 用于为基本数据类型定义一个新的名字,使代码更具可读性或便于修改。
- 示例:
typedef int Integer;
Integer a = 10;
- 这里将
int
类型定义为Integer
,之后就可以使用Integer
来声明变量,就像使用int
一样。这种方式在代码中如果需要频繁使用int
类型,并且希望提高代码可读性(例如,Integer
可能暗示这个int
变量在特定的业务逻辑中有特殊含义)或者在需要修改类型时(比如将int
改为long
),只需要修改typedef
语句即可。
2、指针类型别名
-
可以为指针类型定义别名。
-
示例:
typedef int* IntPtr;
IntPtr p = new int(5);
- 这里
IntPtr
被定义为int*
类型的别名,方便在代码中声明指针变量。这种方式在处理复杂的指针类型(如指向结构体或类的指针)时非常有用,可以简化类型声明。
3、数组类型别名
- 定义数组类型的别名。
- 示例:
typedef int ArrayType[10];
ArrayType myArray;
- 此例中
ArrayType
是一个包含 10 个int
元素的数组类型别名,使用ArrayType
声明变量myArray
就相当于声明了一个int[10]
类型的数组。
二、函数指针类型别名定义
1、函数指针的基本形式
- 在深入
typedef
用法之前,先回顾一下函数指针的基本形式。 - 假设我们有一个函数,其原型如下:
int add(int a, int b);
- 那么指向这个函数的函数指针可以定义为:
int (*func_ptr)(int, int);
- 这里
func_ptr
就是一个函数指针,它可以指向任何具有int
类型参数且返回值为int
的函数,比如可以通过以下方式让它指向add
函数:
func_ptr = add;
2、简单函数指针类型别名
- 用于定义函数指针类型的别名,使函数指针的使用更加方便和清晰。
- 示例:
typedef int (*FuncPtr)();
int myFunction() {
return 1;
}
FuncPtr p = myFunction;
- 首先定义了
FuncPtr
为指向返回int
类型且无参数的函数指针类型。然后定义了一个符合该类型的函数myFunction
,最后将函数myFunction
的地址赋给FuncPtr
类型的变量p
。
3、复杂函数指针类型别名
- 对于带有多个参数和复杂返回类型的函数指针,
typedef
可以大大简化类型声明。 - 示例:
typedef double (*ComplexFuncPtr)(int, int, float);
double myComplexFunction(int a, int b, float c) {
return a + b + c;
}
ComplexFuncPtr p2 = myComplexFunction;
- 这里
ComplexFuncPtr
是指向返回double
类型,带有两个int
参数和一个float
参数的函数指针类型。定义了相应的函数myComplexFunction
后,将其赋值给ComplexFuncPtr
类型的变量p2
。
4、直接赋值与基于 typedef 别名赋值的区别
- 本质相同:
func_ptr = add;
和FuncPtr p = myFunction;
本质上都是将函数地址赋值给函数指针变量,使得可以通过函数指针调用函数。 - 语法形式:
func_ptr = add;
是直接赋值,先定义函数和函数指针,再直接赋值。FuncPtr p = myFunction;
是利用类型别名赋值,先定义类型别名,再定义符合类型的函数,最后赋值。
- 对使用的影响:
- 灵活性和可维护性:使用类型别名的方式更灵活、易维护,修改类型时只需修改
typedef
语句;直接赋值方式若修改类型,可能要多处修改代码。 - 可读性:直接赋值在简单场景直观,复杂场景可读性差;使用类型别名的方式能清晰表达函数指针类型特征,可读性更好。
- 灵活性和可维护性:使用类型别名的方式更灵活、易维护,修改类型时只需修改
三、结构体和类相关用法
1、结构体类型别名
- 为结构体类型定义别名,使代码在使用结构体时更加简洁。
- 示例:
typedef struct {
int x;
int y;
} Point;
Point p;
p.x = 1;
p.y = 2;
- 首先定义了一个匿名结构体,并通过
typedef
将其类型定义为Point
。之后就可以像使用普通类型一样使用Point
来声明变量和访问结构体成员。
2、类类型别名(较少使用)
- 虽然在类中不常用,但也可以为类类型定义别名。
- 示例:
class MyClass {
// 类定义
};
typedef MyClass MyClassAlias;
MyClassAlias obj;
- 这里将
MyClass
定义为MyClassAlias
,可以使用MyClassAlias
来声明MyClass
类型的对象。不过在实际编程中,这种用法相对较少,因为类本身的名称通常已经足够清晰。
四、模板相关用法
1、模板类型别名(C++11 及以上)
- 在 C++11 中,可以使用
typedef
的替代语法using
来定义模板类型别名,这在处理模板相关的复杂类型时非常有用。 - 示例(虽然形式上是
using
,但与typedef
在功能上类似):
template<typename T>
using MyVector = std::vector<T>;
MyVector<int> v;
- 这里定义了一个模板类型别名
MyVector
,它实际上是std::vector<T>
的别名。使用MyVector<int>
就相当于使用std::vector<int>
来声明一个容器对象。
2、在模板编程中的内部类型别名定义
1)基本概念
- 在模板编程中,
typedef
用于在模板类或模板结构体内部定义类型别名。这些类型别名通常与模板参数相关,通过这种方式可以方便地引用和操作基于模板参数的类型,这对于模板的参数化编程和类型推导非常重要。
2)示例解释
- 考虑以下模板结构体:
template<typename T>
struct MyTemplate {
typedef T value_type;
T data;
};
- 在这里,
typedef T value_type;
定义了一个名为value_type
的类型别名,它等同于模板参数T
。 - 当使用
MyTemplate<int>
实例化对象时,value_type
就代表int
类型。例如:
MyTemplate<int> myObj;
MyTemplate<int>::value_type x = myObj.data;
MyTemplate<int> myObj;
这一行实例化了一个int
的模板结构体MyTemplate
。MyTemplate<int>::value_type
用于引用实例化后的模板类MyTemplate<int>
中的类型别名。由于在模板定义中value_type
等同于模板参数T
,当T
为int
时,MyTemplate<int>::value_type
就代表int
类型。
3)应用场景
泛型容器实现
- 在自定义容器模板类(如类似于
std::vector
)的实现中,typedef
用于定义容器所存储元素的类型别名。
template<typename T, typename Allocator = std::allocator<T>>
class MyVector {
typedef T value_type;
// 其他成员和函数定义
};
- 这里的
value_type
可以用于表示容器中元素的类型。例如,在迭代器相关的函数或者对容器元素进行操作的函数中,方便地引用元素类型。
泛型算法实现
- 在编写通用算法模板时,通过
typedef
定义类型别名来获取算法操作对象的类型。
template<typename InputIterator>
typename std::iterator_traits<InputIterator>::value_type sum(InputIterator first, InputIterator last) {
typedef typename std::iterator_traits<InputIterator>::value_type value_type;
value_type result = value_type();
while (first!= last) {
result += *first;
++first;
}
return result;
}
- 在这个
sum
算法中,首先通过std::iterator_traits
获取迭代器所指向元素的类型(使用typedef
定义为value_type
),然后使用这个类型来声明变量result
并进行求和操作。这种方式使得算法可以适用于各种不同类型的迭代器和元素类型。
4)与其他模板特性结合使用
模板特化和部分特化
- 在模板特化或部分特化的情况下,
typedef
定义的类型别名可以根据特化的类型进行相应的变化。
template<typename T>
struct SpecialTemplate {
typedef T general_type;
};
template<>
struct SpecialTemplate<int> {
typedef long long specialized_type;
};
- 在这里,对于一般的模板实例化,
general_type
等同于T
,但在SpecialTemplate<int>
特化的情况下,定义了一个新的类型别名specialized_type
为long long
。这种方式可以根据不同的模板参数类型提供不同的类型定义,增强了模板的灵活性。
继承和模板基类
- 在模板继承的场景中,派生模板类可以使用基类模板中的
typedef
定义的类型别名。
template<typename T>
struct BaseTemplate {
typedef T base_type;
};
template<typename T>
struct DerivedTemplate : public BaseTemplate<T> {
void func() {
base_type variable;
// 对variable进行操作
}
};
- 在
DerivedTemplate
中,通过继承BaseTemplate
,可以使用基类中定义的base_type
(通过typedef
定义)来声明变量,使得代码在继承层次结构中能够统一地引用相关类型。
五、枚举类型别名定义
1、简单枚举类型别名
- 为枚举类型定义别名,方便在代码中使用枚举。
- 示例:
typedef enum {RED, GREEN, BLUE} Color;
Color myColor = RED;
- 定义了一个枚举类型,并通过
typedef
将其命名为Color
,之后可以使用Color
来声明变量并赋值枚举值。
2、增强枚举(C++11 及以上)的别名定义
- 在 C++11 的增强枚举(
enum class
)中,也可以使用typedef
来定义别名。 - 示例:
typedef enum class {UP, DOWN, LEFT, RIGHT} Direction;
Direction dir = Direction::UP;
- 这里为
enum class
类型的枚举定义了别名Direction
,在使用时需要通过Direction::
来访问枚举值,这样可以提高代码的类型安全性。
六、与命名空间结合使用
1、定义命名空间内的类型别名
- 在命名空间内部使用
typedef
来定义类型别名,使命名空间内的类型使用更加方便。 - 示例:
namespace MyNamespace {
typedef int MyInt;
MyInt func() {
return 1;
}
}
MyNamespace::MyInt x = MyNamespace::func();
- 在
MyNamespace
命名空间内定义了MyInt
作为int
类型的别名,并在命名空间内使用这个别名来定义函数func
。在外部访问时,需要通过命名空间限定符来使用这个别名和函数。
2、跨命名空间引用类型别名
- 可以在一个命名空间中引用另一个命名空间内定义的类型别名。
- 示例:
namespace AnotherNamespace {
typedef MyNamespace::MyInt AliasedInt;
AliasedInt y = 2;
}
- 这里
AnotherNamespace
引用了MyNamespace
中的MyInt
类型别名,并重新定义为AliasedInt
,然后使用AliasedInt
来声明变量。