赏金问题:所以,这两个Foo
不是一回事。精细。第二种形式在图书馆中给出。 如果我无法更改它,我如何正确声明它?
我一直以为C和C ++允许重复声明,前提是没有重复的定义。然后我在尝试编写扩展C库的C ++代码时遇到了这个问题。
struct Foo;
typedef struct {} Foo;
这会出现以下错误:
'struct Foo'之前的声明为'struct Foo'
我想转发声明,但是它!这有什么不对?
答案 0 :(得分:40)
您要声明两个名称相同的实体。第一个是struct Foo
,是一个名为Foo
的结构。第二个是匿名结构的别名。
如果你改为:
struct Foo;
struct Foo {};
它有效,因为你在两种情况下都声明了一个名为Foo
的结构。
您无法转发声明匿名结构。您有两种选择:包括整个定义,或更改标题并命名结构。
答案 1 :(得分:38)
typedef-anonymous struct是一种在C ++ 03之前的实践,主要是为了保持与C99之前的编译器的兼容性。
鉴于这是2011年,并且C ++和C都发生了变化,我想知道为什么没有这样一个库的最新版本!
如果它不再处于开发阶段,你就不能“离开”,而只是“生存”并改变它就是这样做的方法。 如果仍在部署中,请将问题提交给开发团队。
如果需要解决方法,请考虑该结构可以继承。 所以,写一个像
这样的前瞻声明struct MyFoo;
并将其定义为
#include "old_library.h"
struct MyFoo: public Foo {};
在您的所有代码中,忘记Foo
并始终使用MyFoo
。
答案 2 :(得分:11)
在类似的情况下,我有一个像
这样的遗留C头== old_library.h ==
typedef struct { int data; } Foo;
== /old_library.h ==
我在自己的C ++类中使用它,作为私有方法的参数:
class C {
void run(Foo *ds);
...
}
为避免C.hpp的#include“old_library.h”,我使用以下前向声明:
class C {
struct Foo;
void run(Foo *ds);
...
}
在C.cpp中我有以下陈述:
extern "C" {
#include "old_library.h"
}
struct C::Foo : public ::Foo {};
这样,我透明地使用C :: Foo而不是Foo,并且不需要MyFoo!
答案 3 :(得分:8)
您不需要在C ++中输入结构:
struct Foo; // Forward declaration
struct Foo
{
}; // Definition
如果您想在C中仅调用Foo
而不是struct Foo
,那么做需要typedef,这也可以通过不同的方式完成:
struct Foo; /* Forward declaration */
struct Foo /* The name is needed here */
{
}; /* Definition */
typedef struct Foo Foo; /* typedef */
或
struct Foo; /* Forward declaration */
typedef struct Foo /* The name is needed here */
{
} Foo; /* Definition and typedef combined */
您当然可以在C和C ++中使用struct Foo
形式。
答案 4 :(得分:5)
您的前瞻性声明声明会有一个名为struct
的{{1}}。
您的第二个声明属于名为Foo
的{{1}}。这些不是一回事。
答案 5 :(得分:2)
对于typedef的前向声明,你需要引用typedeffed的东西,如:
struct foo;
typedef foo bar;
class foo{};
由于你想要转发声明一个匿名结构,你既不能在原始实体的前向声明中给它一个名字,也不能在键入它时引用它。 “逻辑”语法是:
struct ;
typedef bar;
class {};
但是因为这显然是不可能的,所以你不能转发声明匿名结构。
为了达到标准,让我们来看看9.1-2:
仅由类密钥标识符组成的声明;是一个 重新声明当前范围内的名称或转发 将标识符声明为类名。它介绍了这门课程 命名为当前范围。
没有标识符,没有前瞻性声明。
最重要的一点是:避免使用匿名结构,除非它们为您提供了您真正需要的优势。
答案 6 :(得分:2)
恕我直言,只需将typedef
更改为
typedef struct Foo {} Foo;
^^^^^
没有任何伤害,它仍然兼容C& C ++。现在你可以转发声明了它。
[注意:如果您仍然坚持不接触typedef
那么这里就是脏戏。
struct Foo;
#define struct struct Foo
#include"Foo.h" // contains typedef struct {} Foo;
#undef struct
仅当Foo.h
仅包含1 struct
声明时,此方法才有效。我不建议它。]
答案 7 :(得分:2)
您的特定编译器可能会有所不同。
使用MinGW GCC 3.4.5,两个声明都编译时没有错误或警告(使用-Wall
)
struct Foo;
typedef struct {} Foo;
和
struct Foo;
typedef struct Foo {} Foo;
库中是否可能存在前向声明?例如,允许循环指针:
struct Foo;
typedef struct Foo {
struct Foo *fooPtr;
} Foo;
如果库头中已经存在,则会导致您描述的错误。
答案 8 :(得分:1)
为什么不直接拒绝前进。
如果第二个定义位于头文件中,则可以首先在C ++头文件中包含头文件。为了让C ++认为它是C头,在大多数情况下,将#include与extern "C" {
和}
包含在一起就足够了。
答案 9 :(得分:1)
我认为我最近遇到了与原始海报相同的问题,并按照以下方式解决了问题:
我正在编写一个包含第三方提供的API的包装器,定义为:
foo.h中:
typedef struct _foo
{
int i;
} Foo;
Foo* MakeFoo();
int UseFoo(Foo* foo);
我的包装器需要将Foo作为成员,但我不想将Foo暴露给我的包装器的所有使用者。
UberFoo.h:
#pragma once
struct _foo; // forward declare the actual type _foo, not the typedef Foo
class UberFoo
{
public:
UberFoo();
int GetAnswer();
private:
_foo* f;
};
UberFoo.cpp:
#include "UberFoo.h"
#include "Foo.h"
UberFoo::UberFoo()
{
this->f = MakeFoo();
}
int UberFoo::GetAnswer()
{
return UseFoo(f);
}
现在,我的类的使用者可以在不访问_foo / Foo的实际定义的情况下实例化它。如果我需要将指向_foo的指针作为参数传递,或者从函数返回它们以及拥有成员_foo,这也可以。
main.cpp中:
#include <cstdio>
#include "UberFoo.h"
int main(int argc, char* argv[])
{
UberFoo u;
printf( "The Answer = %d\n", u.GetAnswer());
return 0;
}
这里的技巧是转发声明实际的struct类型,而不是typedef'd名称。请注意,结构不是匿名的,这在旧C代码中很常见:
typedef struct // the actual struct type underlying the typedef is anonymous here
{
int i;
} ThisWontWork;
希望这有帮助!
答案 10 :(得分:0)
你无法转发声明它,因为它未命名。它是一个未命名的结构,Foo是一个typedef。
答案 11 :(得分:0)
您正在尝试输入以前使用过的名称。该声明完全有效,只需要使用其他名称。
struct Foo; // Forward declaration of struct Foo
typedef struct {} anotherFoo; // Another structure typedefed
struct Foo {
// Variables
}; // Definition of the forward declared Foo.
请注意,typedef不能以相同的名称使用。