在C++中提前声明结构体指针

4

我正在使用一个第三方库,它有一个声明如下:

typedef struct {} __INTERNAL_DATA, *HandleType;

我想创建一个类,在构造函数中接受一个HandleType

class Foo
{
    Foo(HandleType h);
}

不包括定义HandleType的头文件。通常,我会使用前向声明来实现这样的类型,但是我无法弄清楚语法。我真的想说类似于:

struct *HandleType;

但在GCC中提示“Expected identifier before *”。我唯一能想到的解决方案是这样写我的类:

struct __INTERNAL_DATA;
class Foo
{
    Foo(__INTERNAL_DATA *h);
}

但这依赖于库的内部细节。也就是说,它使用了名称__INTERNAL_DATA,这是一项实现细节。

似乎应该可以在不使用__INTERNAL_DATA(库的实现部分)的情况下,提前声明HandleType(公共API的一部分)。有人知道怎么做吗?

编辑:添加了更多我需要的细节。

5个回答

4

更新:

我正在Foo的实现.cpp中使用它,但是我希望避免在Foo的头文件.h中包含它。也许我只是太过于苛求了? :)

是的,您是的 :) 继续使用前向声明。

如果HandleType是接口的一部分,则必须有一个声明它的头文件。请使用该头文件。

您的问题仍然比较模糊。您试图保护自己免受无法预见的事情的影响,但这是不可能的。

您可以在客户端库中添加以下行:

typedef struct INTERNAL_DATA *HandleType;

但是,如果名称/结构发生变化,您可能会遇到一些转换问题。

尝试使用模板:

template <class T>
class Foo
{
    Foo(T h);
};

前置声明是可以的。如果你要使用指针或引用,只需要在作用域中声明一个类(__INTERNAL_DATA)。然而,如果你要使用成员函数或对象,那么你就需要包含头文件。


但是我需要提前声明__INTERNAL_DATA,这个名称可能会更改或完全删除。(因为它是库的实现细节。) - Jesse Rusak
你可能知道 HandleType 是什么。 - dirkgently
您的需求不够明确,或许您可以添加更多细节。 - dirkgently
HandleType是公共接口的一部分。我应该使用它。__INTERNAL_DATA不是。 - Jesse Rusak
强制转换不占用处理时间。它们是编译器的语法糖。你不能同时拥有模糊和透明度。要么你必须进行大量繁琐的强制转换,要么你必须声明内部结构,让每个人都能看到。 - jmucchiello
显示剩余2条评论

1
 typedef struct {} __INTERNAL_DATA, *HandleType;

如果是这样定义的(都在一行上),那么__INTERNAL DATA就与HandleType一样成为公共接口的一部分。
但是,我不认为__INTERNAL_DATA实际存在。更有可能的是,HandleType实际上(在内部)是一个int。这种奇怪的定义只是一种定义方式,使其与int的大小相同但是不同,以便编译器在您尝试传递int到应该传递HandleType的地方时会给您一个错误。库供应商可以像"int"或"void*"一样定义它,但是这样我们可以获得一些类型检查。
因此,__INTERNAL_DATA只是一种惯例,不会改变。
更新:上面的内容有点小错误...好的,__INTERNAL_DATA绝对不存在。我们知道这一点是事实,因为我们可以看到它被定义为空结构体。我猜第三方库使用了“C”外部链接(没有名称管理),在这种情况下,只需复制typedef--就没问题了。

在库内部,HandleType将具有完全不同的定义;可能是int,也可能是“struct MyStruct {.......} *”。


1
如果类型在第三方库中,则前向声明(由于头文件更改而隔离重建)的巨大优势实际上会丧失。
如果您担心编译时间(它是一个相当大的头文件),那么也许您可以将其放置在预编译头文件中,或者只从库中包含相关头文件。
例如,许多库头文件看起来像。
// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"

1

我不太确定你的意图,但是以下代码可以正常工作,而无需包含实际的头文件:

// foo.h
class Foo
{
    public:
    template<typename T>Foo(T* h) { /* body of constructor */ }
};

请注意,在构造函数的主体中仍然需要访问__INTERNAL_DATA的公共成员。 编辑:正如James Curran指出的那样,__INTERNAL_DATA结构没有成员,因此可以像上面那样使用,没有问题。

仔细检查typedef... __INTERNAL_DATA没有公共(或私有)成员... - James Curran
我认为那只是一个简单的例子结构,方便问题的阐述。 - e.James

1

如果你真的、真的、真的不想向调用者公开_INTERNAL_DATA,那么你唯一的选择就是使用typedef void* HandleType;然后在库内部,你可以做任何你想做的事情,包括更改整个*HandleType的实现。

只需创建一个辅助函数来访问你的真实数据即可。

inline _INTERNAL_DATA* Impl(HandleType h) {
    return static_cast<_INTERNAL_DATA*>(h);
}

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