Форвард объявить указатели на структуры в C ++ - PullRequest
3 голосов
/ 10 марта 2009

Я использую стороннюю библиотеку, которая имеет объявление, подобное этому:

typedef struct {} __INTERNAL_DATA, *HandleType;

И я хотел бы создать класс, который принимает HandleType в конструкторе:

class Foo
{
    Foo(HandleType h);
}

без , включая заголовок, который определяет HandleType . Обычно я просто объявляю такой тип вперед, но не могу понять синтаксис для этого. Я действительно хочу сказать что-то вроде:

struct *HandleType;

Но это говорит "Ожидаемый идентификатор до *" в GCC. Единственное решение, которое я вижу, это написать мой класс так:

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

Но это зависит от внутренних деталей библиотеки. То есть он использует имя __INTERNAL_DATA, которое является подробностью реализации.

Похоже, что можно сделать предварительное объявление HandleType (часть публичного API) без использования __INTERNAL_DATA (часть реализации библиотеки.) Кто-нибудь знает, как?

РЕДАКТИРОВАТЬ: Добавлено больше информации о том, что я ищу.

Ответы [ 5 ]

4 голосов
/ 10 марта 2009

Обновление:

Я использую его в реализации .cpp Foo, но я хочу избежать включения его в мой заголовок .h для Foo. Может я просто слишком педантичен? :)

Да, вы есть :) Продолжите предварительную декларацию.

Если HandleType является частью интерфейса, должен быть заголовок, объявляющий это. Используйте этот заголовок.

Ваша проблема все еще неясна. Вы пытаетесь защитить от чего-то, что вы не можете.

Вы можете добавить следующую строку в свою клиентскую библиотеку:

typedef struct INTERNAL_DATA *HandleType;

но, если имя / структура изменится, вас может подстерегать какая-то злоба.

Попробуйте шаблоны:

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

Вперед декларация в порядке. Если вы собираетесь использовать указатели или ссылки, вам нужно только объявление класса (__INTERNAL_DATA) в области видимости. Однако, если вы собираетесь использовать функцию-член или объект, вам нужно будет включить заголовок.

1 голос
/ 10 марта 2009

Если вы действительно, действительно, действительно не хотите предоставлять _INTERNAL_DATA вызывающей стороне, тогда ваш единственный реальный выбор - использовать typedef void * HandleType ; Затем внутри вашей библиотеки вы можете делать все, что захотите, включая изменение всей реализации * HandleType.

Просто создайте вспомогательную функцию для доступа к вашим реальным данным.

inline _INTERNAL_DATA* Impl(HandleType h) {
    return static_cast<_INTERNAL_DATA*>(h);
}
1 голос
/ 10 марта 2009

Я не совсем уверен, что вы собираетесь, но следующее будет работать без включения самого файла заголовка:

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

Имейте в виду, вы все равно должны иметь доступ к открытым членам __INTERNAL_DATA в теле конструктора.

edit: , как указал Джеймс Керран, структура __INTERNAL_DATA не имеет членов, поэтому ее можно использовать, как указано выше, без проблем.

1 голос
/ 10 марта 2009

Если тип находится в сторонней библиотеке, то большое преимущество прямого объявления (изолирование перестроений из-за изменений в заголовках) фактически теряется.

Если вас беспокоит время компиляции (это большой заголовок), возможно, вы можете поместить его в предварительно скомпилированный заголовок или просто включить соответствующий заголовок из библиотеки.

например. многие заголовки библиотек выглядят как

// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"
1 голос
/ 10 марта 2009
 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 {.......} *".

...