Прямое объявление указателей на структуры в C ++

StackOverflow https://stackoverflow.com/questions/631952

  •  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 не имеет членов, поэтому ее можно использовать, как указано выше, без проблем.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top