在Objective-C中进行结构体的前向声明

16

我正在创建一个协议,其中我定义的一个方法的参数是CMTime*。我想要使用前向声明CMTime而不是包含它。但是,我尝试了@class CMTime,它抱怨说在其他地方重新定义了不同类型的符号。文档显示它是一个结构体。我已尝试将其作为前向声明:

struct CMTime;
但它仍然抱怨说它不知道它是什么。有没有任何想法我做错了什么?

2
不幸的是,它使用匿名结构体声明。这意味着你要么必须复制整个声明(并希望它永远不会改变),要么只能包含头文件。 - ughoavgfhw
1
@ughoavgfhw 复制它并不好(很可能两个声明最终会在同一个TU中)。除此之外,考虑到 CMTime 的声明方式,我认为这已经算是一个具体的答案了。 - justin
@Justin,我只是建议这样做,因为他说他不打算包含头文件,但现在我想了想,他在尝试创建一个类时遇到了一个已经被定义的错误,这表明头文件已经被包含了。如果有人能解释一下,我可能会把它作为答案发布。 - ughoavgfhw
@ughoavgfhw 可能是因为原帖作者在使用时忘记或省略了 struct 标签。void foo(CMTime*)void foo(struct CMTime*) 的区别。 - justin
你应该接受Justin的答案。 - Arseniy Banayev
3个回答

18

如果源代码以ObjC编译,则在这方面具有与C相同的规则。

如果源代码以ObjC++编译,则在这方面具有与C++相同的规则。

@class MONClass;是一种ObjC类型的前向声明。不要用于结构体。

struct t_mon_struct;是命名的C或C++结构体的前向声明。不要用于ObjC类型。从技术上讲,编译器允许你将C++类作为结构体进行前向声明(前提是该类也在全局命名空间中声明)。

因此,在这里,所有语义的根源都归结为C(假设这是一个ObjC翻译)。我现在不再提及ObjC和C++。

这里有一些常见的复杂性来源:

  • 结构体命名空间
  • 结构体的声明
  • 避免标签的重复定义

struct t_mon_struct;是标记结构体的前向声明。具体而言,该名称存在于结构体命名空间中。

一个存在于结构体命名空间中的标记结构体:

struct t_mon_struct { int a; };

全局命名空间中带有typedef的匿名结构体:

typedef struct { int a; } t_mon_struct;

全局名称空间中具有typedef的标记结构体:

typedef struct t_mon_struct { int a; } t_mon_struct;

CMTime的声明如下:

typedef struct
{
    CMTimeValue    value;
    CMTimeScale    timescale;
    CMTimeFlags    flags;
    CMTimeEpoch    epoch;
} CMTime;

具体来说,全局的typedef标签CMTime绑定到一个匿名结构体中的结构命名空间,并且除非其声明可见,否则不能引用它。

如果CMTime已经声明:

typedef struct CMTime
{
    CMTimeValue    value;
    CMTimeScale    timescale;
    CMTimeFlags    flags;
    CMTimeEpoch    epoch;
} CMTime;

那么你可以通过使用前向声明 struct CMTime 来解决问题:

struct CMTime;
void foo(struct CMTime*);

由于它没有被声明,所以您需要#include其声明,或设计一个解决方案。

当结构体的typedef与其标记不同时,问题会变得更加复杂。在C语言中,您不能绑定到或重新声明typedef。但是,您可以通过在结构体命名空间中使用名称来绕过它 - 这被一些库作者视为私有内容。


1

在结构体之前加上typedef对我来说就可以了。

typedef struct CMTime;

0

如果您想让具有前向声明的文件了解结构体的内容,它们需要导入定义该结构体的头文件(可以在多个位置)。如果您不需要访问其属性,则可以前向声明结构体,但仅限于此。


1
非常抱歉(需要学习如何使用谷歌:P)- 现在编辑答案。我的答案现在正确吗? - jrtc27
到那儿还有很多复杂的地方,不仅仅是那样简单。 - justin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接