如何创建类型定义结构的前向声明

时间:2018-09-18 13:37:33

标签: c++ forward-declaration

我有1个.h文件test.h,其中包含一个类。在此类中,有一个私有方法,该方法在我不想设为“公开”的类型上返回指针,但我希望能够将此test.h文件包含在其他源文件中。

通常,在.h文件中使用前向声明很容易:

class Foo;

但是问题是这种类型来自C文件,我无法更改(因为我没有维护其他代码),并且它是typedef

所以基本上我的test.cpp是:

// this type comes from a C file, cannot be changed to struct or class
typedef struct 
{
   int x;
} Foo;

#include "test.h"

static Foo foo;

Foo *Test::private_function()
{
  foo.x = 12;
  return &foo;
}

int Test::compute()
{
   auto *local_foo = private_function();
   return local_foo->x;
}

我的test.h文件是:

#pragma once

struct Foo;

class Test
{
public:
  Test() {}
  int compute();
private:
  Foo *private_function();
};

尝试编译失败:

>g++ -std=c++11 -c test.cpp
In file included from test.cpp:10:0:
test.h:3:8: error: using typedef-name 'Foo' after 'struct'
test.cpp:7:3: note: 'Foo' has a previous declaration here

目前,我的解决方法是返回void *并来回执行static_cast,但是我没有找到最佳选择。有更好的解决方案吗?

(我已经检查过Forward declaration of a typedef in C++,但我测试了解决方案,但它们似乎不适用于我的情况,也许我想做的事比较简单/不同-我只有.h和.cpp-或根本不可能)

2 个答案:

答案 0 :(得分:1)

返回此:

//#include "SecretFoo.h"
struct SecretFoo {
  uintptr_t handle;
};

//#include "SecretFooImpl.h"
#include "SecretFoo.h"
#include "Foo.h" // definition of typedef struct {int x;} Foo;
Foo* Crack( SecretFoo foo ) {
  return reinterpret_cast<Foo*>(foo.handle);
}
SecretFoo Encase( Foo* foo ) {
  return {reinterpret_cast<uintptr_t>(foo)};
}

现在我们得到:

#include "SecretFooImpl.h"
static Foo foo;

SecretFoo Test::private_function()
{
  foo.x = 12;
  return Encase(&foo);
}

int Test::compute()
{
   auto *local_foo = Crack(private_function());
   return local_foo->x;
}

并在标题中:

#pragma once
#include "SecretFoo.h"

class Test
{
public:
  Test() {}
  int compute();
private:
  SecretFoo private_function();
};

这归结为相同的二进制代码,但是SecretFoo和成对的Crack / Encase函数提供了比void*更安全的类型转换。


此技术有时在C语言世界中使用。 SecretFoo是一种句柄;不透明的指针状结构。在这种情况下,其中的数据(uintptr_t handle)只是强制转换指针;但它可以是指向指针表的指针或其他任何指针。 CrackEncase方法是唯一允许访问/创建SecretFoo的方法。

答案 1 :(得分:0)

不幸的是,不能向前声明typedef。

一个常见的解决方法是有一个C ++类,该类从C结构继承,并由其typedef引用,您可以对此进行声明。这将需要对代码进行一些更改,但应尽量减少。

(代表发表评论的https://stackoverflow.com/users/3943312/sam-varshavchik的人)