Прямое объявление указателей на структуры в C ++
-
08-07-2019 - |
Вопрос
Я использую стороннюю библиотеку, которая имеет объявление, подобное этому:
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 (часть реализации библиотеки). Кто-нибудь знает, как это сделать?
Редактировать:Добавлено более подробное описание того, что я ищу.
Решение
Обновить:
Я использую его в implementation .cpp Foo, но я хочу избежать включения его в мой header .h для Foo.Может быть, я просто слишком педантичен?:)
Да, это так :) Продолжайте с предварительным объявлением.
Если HandleType является частью интерфейса, то должен быть заголовок, объявляющий это.Используйте этот заголовок.
Ваша проблема по-прежнему остается неясной.Вы пытаетесь защититься от чего-то, чего не можете.
Вы можете добавить следующую строку в свою клиентскую библиотеку:
typedef struct INTERNAL_DATA *HandleType;
но, если название / структура изменятся, вас может ожидать какая-нибудь гадость с кастингом.
Попробуйте шаблоны:
template <class T>
class Foo
{
Foo(T h);
};
Прямое объявление - это нормально.Если вы собираетесь использовать указатели или ссылки, вам нужен только класс (__INTERNAL_DATA
) декларация по сфере применения.Однако, если вы собираетесь использовать функцию-член или объект, вам нужно будет включить заголовок.
Другие советы
Если тип находится в сторонней библиотеке, то большое преимущество прямого объявления (изолирующее перестроение из-за изменений в заголовках) фактически теряется.
Если вы беспокоитесь о времени компиляции (это большой заголовок), то, возможно, вы можете поместить его в предварительно скомпилированный заголовок или просто включить соответствующий заголовок из библиотеки.
Например.многие заголовки библиотек выглядят следующим образом
// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"
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 {.......} * ".
Если вы действительно, действительно, действительно не хотите показывать _INTERNAL_DATA вызывающей стороне, тогда ваш единственный реальный выбор - использовать typedef void * HandleType ; Затем внутри вашей библиотеки вы можете делать все, что захотите, включая изменение всей реализации * HandleType.
Просто создайте вспомогательную функцию для доступа к вашим реальным данным.
inline _INTERNAL_DATA* Impl(HandleType h) {
return static_cast<_INTERNAL_DATA*>(h);
}
Я не совсем уверен, что вы собираетесь, но следующее будет работать без включения самого файла заголовка:
// foo.h
class Foo
{
public:
template<typename T>Foo(T* h) { /* body of constructor */ }
};
Имейте в виду, вам все равно придется иметь доступ к открытым членам __ INTERNAL_DATA
в теле конструктора.
edit: , как указал Джеймс Керран, структура __ INTERNAL_DATA
не имеет членов, поэтому ее можно использовать, как указано выше, без проблем.