Это полностью переписанная версия предыдущего вопроса ; Я думаю, что в первой версии пропущены важные детали; этот обеспечивает весь контекст.
У меня есть заголовок некоторого C ++ API. API объявляет несколько классов, подобных этому:
class Foo
{
public:
inline void Bar(void);
/* more inlines */
private:
inline Foo();
/* maybe more inline constructors */
}
т.е. нет членов, все функции встроенные и открытые, кроме конструкторов. Конструкторы являются частными, поэтому, насколько я понимаю C ++, я не могу их назвать. Для создания этих объектов я должен использовать auto_ptr
s для них:
class FooAutoPtr : public std::auto_ptr<Foo>
{
public:
inline FooAutoPtr();
/* one for each Foo constructors */
}
API также имеет второй набор функций, таких как:
void Foo_Bar(void *self);
Foo* Foo_Constructor();
Давайте назовем их основные функции , потому что это символы, фактически экспортированные из хост-приложения. Не классы C ++.
Основные функции имеют связь C (то есть они объявлены как extern "C"
), но они объявлены как принимающие и возвращающие типы C ++ (например, они могут принимать ссылку: Foo &foo
). Наконец, заголовок содержит реализацию встроенных функций классов C ++. Все эти функции делают то же самое: они вызывают основные функции. Например, конструктор FooAutoPtr
выглядит следующим образом:
inline FooAutoPtr::FooAutoPtr()
{
reset(Foo_Constructor());
}
Насколько я понимаю, код получает некоторый объект, который должен быть указателем на Foo
, от хост-приложения и изменяет гизмо auto_ptr
, чтобы указывать на этот объект. Но для разработчика это выглядит так, как будто это истинный указатель на Foo
. И звонок Foo::Bar()
выглядит так:
inline Foo::Bar()
{
Foo_Bar(this);
}
Это относится ко всем классам и методам C ++. Умно, а?
Теперь, может кто-нибудь объяснить, что все это значит? :) Это не настоящий C ++ API, не так ли? Для меня это больше похоже на тонкую оболочку C ++ поверх C API. Если это так, можно ли переопределить основные функции, чтобы потерять биты C ++ ? Я понимаю, как написать обертку C для C ++ (на самом деле, я ее уже написал), но, если возможно, я бы предпочел потерять обертку и использовать функции напрямую. Но как мне потерять C ++?
Например, может быть функция со ссылками:
Bar& Foo_GetBar(void* self, const Baz& baz, int& i);
Прямо сейчас я вызываю это из моей оболочки C ++ так:
typedef struct bar bar_t; /* and others */
/*...*/
bar_t*
foo_get_bar(foo_t* foo, baz_t* baz, int* i)
{
return (bar_t*) &Foo_GetBar(foo, *(Baz*)baz, *i);
}
и это работает (понятия не имею, как). Но я бы предпочел, чтобы он был переопределен так:
/* type? */ Foo_GetBar(foo_t*, /* type? /*, /* type? */);
ОБНОВЛЕНИЕ : Я нашел интересную вещь, которая подтверждает ответ Нейла . Это код в Common Lisp, который использует тот же API. (Естественно, он должен использовать часть C.) И, исходя из того, что я (едва) могу прочитать в источнике, автор просто использовал указатели вместо ссылок. Вот фрагмент кода, который преобразует объявления C ++ в Lisp:
;; use * instead of & - we're not interested in C++ details
line (regex-replace-all "&" line "*")
Вот и все :) Спасибо всем!