我什么时候应该在 C + + 中使用 typedef?

在我多年的 C + + (MFC)编程生涯中,我从未觉得有必要使用 typedef,所以我真的不知道它是用来做什么的。我应该在哪里使用它?是否存在使用 typedef为首选的实际情况?或者这真的是一个 C 特定的关键字?

62678 次浏览

Typedef 的实际用法:

  • 为冗长的模板类型提供友好的别名
  • 为函数指针类型提供友好的别名
  • 为类型提供本地标签,例如:

    template<class _T> class A
    {
    typedef _T T;
    };
    
    
    template<class _T> class B
    {
    void doStuff( _T::T _value );
    };
    

模板超编程

对于许多 模板超编程任务,typedef有需要——每当一个类被视为“编译时类型函数”时,typedef就被用作“编译时类型值”来获得结果类型。例如,考虑一个将指针类型转换为基类型的简单元函数:

template<typename T>
struct strip_pointer_from;


template<typename T>
struct strip_pointer_from<T*> {   // Partial specialisation for pointer types
typedef T type;
};

示例: 类型表达式 strip_pointer_from<double*>::type的计算结果为 double。请注意,模板超编程在图书馆发展之外并不常用。

简化函数指针类型

typedef很有帮助,为复杂的函数指针类型提供一个简短、尖锐的别名:

typedef int (*my_callback_function_type)(int, double, std::string);


void RegisterCallback(my_callback_function_type fn) {
...
}

只要它使源代码更清晰或更好地阅读。

我在 C # 中对泛型/模板使用 kind of typedef。“ NodeMapping”比“ Dictionary < string,XmlNode >”更适合阅读/使用和理解。恕我直言。因此,我建议将其用于模板。

和函数指针一起使用

用 typedef 隐藏函数指针声明

void (*p[10]) (void (*)() );

只有少数程序员能说出 p 是一个“由10个指向返回 void 的函数的指针组成的数组,并且带有一个指向另一个返回 void 且不带参数的函数的指针。”这种繁琐的语法几乎无法破译。但是,可以通过使用 typedef 声明来大大简化它。首先,为“返回 void 且不接受任何参数的函数的指针”声明 typedef,如下所示:

  typedef void (*pfv)();

接下来,根据我们之前声明的 typedef,为“返回 void 并获取 pfv 的函数的指针”声明另一个 typedef:

 typedef void (*pf_taking_pfv) (pfv);

现在我们已经创建了 pf _ taking _ pfv typedef 作为笨拙的“指向返回 void 并接受 pfv 的函数的指针”的同义词,声明一个包含10个这样的指针的数组简直是小菜一碟:

  pf_taking_pfv p[10];

开始

在 Bjarne 的书中,他指出您可以使用 typedef 来处理具有不同整数大小的系统之间的可移植性问题。(这是一个解释)

sizeof(int)为4的机器上,你可以

typedef int int32;

然后在代码的任何地方使用 int32。当您转移到 C + + 的实现时,其中 sizeof(int)为2,那么您只需更改 typdef即可

typedef long int32;

你的程序仍然会在新的实现上工作。

Typedef 在很多情况下都很有用。

基本上,它允许您为类型创建别名。当/如果您必须更改类型时,代码的其余部分可以保持不变(当然,这取决于代码)。 例如,假设您想对一个 c + + 向量进行 ITER

vector<int> v;


...


for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) {


// Stuff here


}

在将来,您可能会考虑使用列表来更改向量,因为您必须对它执行的操作类型。如果没有 typedef,则必须更改代码中出现的所有向量。 但是如果你这样写:

typedef vector<int> my_vect;


my_vect v;


...


for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) {


// Stuff here


}

现在你只需要改变一行代码(即从“ typedef vector<int> my_vect”到“ typedef list<int> my_vect”) ,一切就都可以正常工作了。

Typedef 还可以节省您的时间,因为复杂的数据结构写起来很长(而且很难读)

使用 typedef 的一个很好的理由是,某些内容的类型可能会发生变化。例如,假设目前,16位 int 可以用于索引某些数据集,因为在可预见的未来,您将只有少于65535个条目,并且空间限制很大,或者您需要良好的缓存性能。但是,如果您需要在一个包含超过65535个项目的数据集上使用程序,那么您希望能够轻松地切换到一个更广泛的整数。使用 typedef,您只需要在一个地方更改它。

只是提供一些例子的东西说: STL 容器。

 typedef std::map<int,Froboz> tFrobozMap;
tFrobozMap frobozzes;
...
for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
{
...
}

甚至使用类似以下的 typedef 也是很正常的

typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;

另一个例子: 使用共享指针:

class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;

[更新] 根据评论-把它们放在哪里?

最后一个例子-使用 shared_ptr-是很容易的: 是真正的标题材料-或者至少是一个向前的标题。无论如何,您都需要 share _ ptr 的前向声明,它的一个优点是可以安全地使用 forward decl。

换句话说: 如果存在 share _ ptr,那么您可能只应该通过 share _ ptr 使用该类型,因此分隔声明没有多大意义。

(是的,xyzfwd.h 是一个痛苦。我只会在热点地区使用它们——因为我知道热点地区很难识别。要怪就怪 C + + 编译 + 链接模型...)

我通常在声明容器变量时使用 Container typedef-例如,在本地声明一个局部变量,在实际的容器实例是一个类成员时作为类成员。如果实际的容器类型是一个实现细节,那么这种方法可以很好地工作——不会产生额外的依赖性。

如果它们成为 特别接口的一部分,它们将与使用它们的接口一起声明,例如。

// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes);

当类型是不同接口之间的绑定元素时,就会出现问题——也就是说,多个头需要相同的类型。一些解决方案:

  • 与包含的类型一起声明它 (适用于经常使用的容器)
  • 将它们移动到单独的标头
  • 移动到一个单独的头部,并使其成为一个数据类,其中实际的容器再次成为实现细节

我同意后两者都不是很好,我只会在遇到麻烦的时候使用它们(不会主动使用)。

枚举或结构不需要 Typedef。

是吗?

typedef enum { c1, c2 } tMyEnum;
typedef struct { int i; double d; } tMyStruct;

可以写得更好

enum tMyEnum { c1, c2 }
struct  tMyStruct { int i; double d; };

对吗,那 C 呢?

typedef不仅允许为复杂类型提供别名,而且还为记录类型提供了一个自然的位置。我有时用它来记录文档。

也有时候我使用字节数组。现在,字节数组可能意味着很多东西。typedef可以方便地将字节数组定义为“ hash32”或“ fileContent”,从而使代码更具可读性。

当我们想要启用一种 集装箱独立代码(但不是完全启用)时,使用 typedef 还有另外一种用例

假设你有品位:

Class CustomerList{


public:
//some function
private:
typedef list<Customer> CustomerContainer;
typedef CustomerContainer::iterator Cciterator;
};

上面的代码使用 typedef 封装了内部容器实现,即使将来列表容器需要更改为 Vector 或 deque,CustomerList 类的用户也不需要担心确切的容器实现。

因此,typedef 封装并在一定程度上帮助我们编写容器独立的代码

Typedef 允许类的灵活性。如果要更改程序中的数据类型,则不需要更改多个位置,只需更改一个事件。

typedef <datatype example  int or double> value_type

您可以使用 nay 而不是 value_type,但是 value_type通常是标准名称。

所以你可以像这样使用 typedef

value_type i=0;     //same as a int or double i=0;

typedef的一个实际例子是 size_t。它保证足够大以容纳主机系统能够处理的最大对象的大小。最大允许大小取决于编译器; 如果编译器是32位,那么对于 unsigned int来说它只是一个 typedef,但是如果编译器是64位,那么对于 unsigned long long来说它就是一个 typedefsize_t数据类型永远不会是负数。