Как создать прямое объявление структуры typedef - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть 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 назад и вперед, но я не нахожу это оптимальным.Есть ли более приятное решение?

(я проверил прямое объявление typedef в C ++ , но я проверил решения, и они, похоже, не работают в моем случае, может быть, то, что я хочусделать проще / иначе - у меня есть только .h и .cpp - или просто невозможно)

1 Ответ

0 голосов
/ 18 сентября 2018

Возвращаем это:

//#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*.


Этот метод иногда используется в мире Си.SecretFoo - это своего рода ручка;непрозрачная структура, похожая на указатель.Данные в нем (uintptr_t handle) в этом случае являются просто указателем приведения;но это может быть указатель на таблицу указателей или что-то еще.Методы Crack и Encase являются единственными способами, позволяющими получить доступ к / создать SecretFoo.

.
...