2009-03-10 3 views
3

Я использую 3-й библиотеку партии, которая имеет декларацию, как это:вперед объявить указатели к структурам в C++

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 (часть реализации библиотеки). Кто-нибудь знает как?

EDIT: Добавлено более подробное описание того, что я ищу.

ответ

4

Update:

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

Да, вы: Продолжайте форвардную декларацию.

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

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

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

typedef struct INTERNAL_DATA *HandleType; 

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

Try шаблоны:

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

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

+0

, но тогда мне нужно переслать-объявить __INTERNAL_DATA, это имя, которое может быть изменено или вообще удалено. (Так как это деталь реализации библиотеки.) –

+0

Так может быть HandleType для всего, что вы знаете. – dirkgently

+0

Ваши требования не ясны, возможно, вы можете добавить более подробную информацию. – dirkgently

1
typedef struct {} __INTERNAL_DATA, *HandleType; 

Если она определяется так (все в одной строке), то __INTERNAL DATA является такой же частью открытого интерфейса, как HandleType.

Однако, я не думаю, что __INTERNAL_DATA действительно существует.Скорее всего, HandleType действительно (внутренне) int. Это нечетное определение - это просто способ его определения, чтобы он был такого же размера, как и int, но отличался, так что компилятор выдавал вам ошибку, если вы попытаетесь передать int, где вы должны передать HandleType. Поставщик библиотеки мог так же легко определить его как «int» или «void *», но таким образом мы получаем некоторую проверку типов.

Следовательно __INTERNAL_DATA - это просто конвенция и не изменится.


UPDATE: Выше было немного психического отрыжка ... ОК, __INTERNAL_DATA определенно не существует. Мы знаем это для факта, потому что мы можем см.. Это определение как пустая структура. Я собираюсь догадаться, что сторонняя библиотека использует внешнюю связь C (без управления именами), и в этом случае просто скопируйте typedef - все будет хорошо.

В самой библиотеке HandleType будет иметь совершенно другое определение; возможно int, может быть, "struct MyStruct {.......} *".

1

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

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

E.g. многие заголовки библиотеки выглядеть

// library.h 
#include "Library/Something.h" 
#include "Library/SomethingElse.h" 
1

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

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

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

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

+0

Проверьте typedef близко ... __INTERNAL_DATA не имеет публичных (или частных) членов .... –

+0

Я предположил, что это была просто примерная структура, чтобы вопрос оставался простым. –

+0

... но я вижу ваш пункт. Ответ обновлен. –

1

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

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

inline _INTERNAL_DATA* Impl(HandleType h) { 
    return static_cast<_INTERNAL_DATA*>(h); 
} 
Смежные вопросы