c++ - how to create a forward declaration of a typedef struct
问题描述
I have 1 .h file test.h
containing a class. In this class there's a private method returning a pointer on a type I don't want to make "public", but I want to be able to include this test.h
file in other source files.
In general, it's easy to use a forward declaration in the .h file:
class Foo;
But the problem is that this type comes from a C file that I cannot change (because it's someone else code that I'm not maintaining) and it's a typedef
.
So basically my test.cpp
is:
// 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;
}
and my test.h
file is:
#pragma once
struct Foo;
class Test
{
public:
Test() {}
int compute();
private:
Foo *private_function();
};
trying to compile that fails:
>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
Currently my workaround is to return void *
and perform static_cast
back and forth, but I don't find that optimal. Is there a nicer solution?
(I have checked Forward declaration of a typedef in C++ but I tested the solutions and they don't seem to work in my case, maybe what I want to do is simpler/different - I have just a .h and .cpp - or just not possible)
解决方案
Return this:
//#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)};
}
now we get:
#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;
}
and in your header:
#pragma once
#include "SecretFoo.h"
class Test
{
public:
Test() {}
int compute();
private:
SecretFoo private_function();
};
this boils down to the same binary code, but the SecretFoo
and paired Crack
/Encase
functions provide a safer kind of casting than just a void*
.
This technique is sometimes used in the C world. SecretFoo
is a kind of handle; an opaque pointer-like structure. The data in it (the uintptr_t handle
) is in this case just a cast pointer; but it could be a pointer into a table of pointers or whatever else. The Crack
and Encase
methods are the only ways permitted to access/create the SecretFoo
.
推荐阅读
- java - 在 apache Beam 管道中解析 CSV 以将其发布到 Google pubsub
- c++ - 如何在子类中调用特定的模板方法(用 CRTP 继承 - 解决方案)
- java - 使用远程 SSO 服务器保护 spring websockets
- swift - swift 4 在 UIRefeshControl 之前清空 UITableView
- javascript - 如何将徽标添加到具有 CSS/HTML/JS 和引导程序的网站
- bash - 在 OSX 中展平文件结构时自动覆盖
- spring-boot - “我需要一个类型的 bean”错误:Spring-boot
- windows - 在用户开始菜单 CSIDL_STARTMENU 中创建快捷方式的正确方法
- c# - c#大双打比较
- javascript - 导入不带转义引号的 csv javascript