C ++中'struct'和'typedef struct'的区别?
在C ++中,是否有任何区别:
struct Foo { ... };
和
typedef struct { ... } Foo;
在C ++中,只有一个微妙的区别。 这是来自C的一个延期,它在这方面有所作为。
C语言标准(C89§3.1.2.3,C99§6.2.3和C11§6.2.3)为不同类别的标识符分别命名空间,包括标签标识符(用于struct
/ union
/ enum
)和普通标识符(用于typedef
和其他标识符)。
如果你只是说:
struct Foo { ... };
Foo x;
你会得到一个编译器错误,因为Foo
只在标签命名空间中定义。
您必须将其声明为:
struct Foo x;
任何时候你想引用一个Foo
,你都必须把它称为一个struct Foo
。 这会让人讨厌,所以你可以添加一个typedef
:
struct Foo { ... };
typedef struct Foo Foo;
现在, struct Foo
(在标记名称空间中)和简单的Foo
(在普通标识符名称空间中)都指向相同的事物,并且您可以在不使用struct关键字的情况下自由声明Foo
类型的对象。
构造:
typedef struct Foo { ... } Foo;
只是声明和typedef
的缩写。
最后,
typedef struct { ... } Foo;
声明一个匿名结构并为其创建一个typedef
。 因此,使用此构造,它在标记名称空间中没有名称,而只有typedef名称空间中的名称。 这意味着它也不能被提前宣布。 如果你想做一个前向声明,你必须在标签名称空间中给它一个名字。
在C ++中,只要名称不被具有相同名称的另一个声明隐藏,所有的struct
/ union
/ enum
/ class
声明都会像隐式地typedef
一样操作。 请参阅Michael Burr的答案以获取详细信息。
在这篇DDJ文章中,Dan Saks解释了一个小的区域,如果你没有键入你的结构(和类!),那么错误可能会蔓延开来:
如果你愿意,你可以想象C ++为每个标签名称生成一个typedef,例如
typedef class string string;
不幸的是,这并不完全准确。 我希望这很简单,但事实并非如此。 C ++不能为结构体,联合体或枚举生成这样的typedef,而不会引入与C的不兼容性。
例如,假设一个C程序声明了一个名为status的函数和一个结构体:
int status(); struct status;
再次,这可能是不好的做法,但它是C.在这个程序中,状态(本身)是指功能; 结构状态指的是类型。
如果C ++自动为标记生成了typedef,那么当你将这个程序编译为C ++时,编译器会生成:
typedef struct status status;
不幸的是,这个类型名称与函数名称冲突,程序无法编译。 这就是为什么C ++不能简单地为每个标签生成一个typedef。
在C ++中,标记的作用与typedef名称相似,只不过程序可以声明与标记名称相同且范围相同的对象,函数或枚举器。 在这种情况下,对象,函数或枚举器名称将隐藏标记名称。 该程序只能通过在标签名称前使用关键字class,struct,union或enum(如适用)来引用标签名称。 由这些关键字后跟一个标签组成的类型名称是一个详细说明类型说明符。 例如,struct status和enum month是详细说明类型说明符。
因此,一个包含以下两者的C程序:
int status(); struct status;
在编译为C ++时表现相同。 单独的名称状态是指该功能。 程序只能通过使用elaborated-type-specifier结构状态来引用该类型。
那么这是如何让错误进入程序的呢? 考虑清单1中的程序。该程序定义了一个具有默认构造函数的类foo,以及一个将foo对象转换为char const *的转换运算符。 表达方式
p = foo();
主要应构造一个foo对象并应用转换运算符。 随后的输出语句
cout << p << 'n';
应该显示类foo,但它不会。 它显示函数foo。
出现这个令人惊讶的结果是因为程序包含了清单2所示的头文件lib.h。该头文件定义了一个名为foo的函数。 函数名称foo隐藏了类名foo,因此在main中对foo的引用是指函数,而不是类。 main可以仅通过使用详细类型说明符来引用该类,如同
p = class foo();
在整个程序中避免这种混淆的方法是为类名foo添加以下typedef:
typedef class foo foo;
紧接在类定义之前或之后。 该typedef导致类型名称foo和函数名称foo(来自库)之间的冲突,这会触发编译时错误。
我知道没有人真的写这些typedefs是理所当然的。 它需要很多纪律。 由于清单1中错误的发生率可能很小,所以很多情况下都不会出现这种问题。 但是,如果软件中的错误可能会导致人身伤害,那么无论出现错误的可能性如何,您都应该写入typedef。
我无法想象为什么有人会想要在类的作用域中隐藏一个具有函数或对象名的类名。 C中的隐藏规则是一个错误,它们不应该被扩展到C ++中的类。 事实上,你可以纠正错误,但它需要额外的编程纪律和努力,而这不需要。
一个更重要的区别是: typedef
不能被前向声明。 所以对于typedef
选项,则必须#include
包含文件typedef
,这意味着一切#include
是你.h
还包括该文件是否直接需要与否,等等。 它肯定会影响您在大型项目上的构建时间。
没有typedef
,在某些情况下,您可以添加struct Foo;
的前向声明struct Foo;
在你的上面.h
文件,只有#include
在你的结构定义.cpp
文件。
上一篇: Difference between 'struct' and 'typedef struct' in C++?
下一篇: Strange behavior when compiler converts from float to double