Как получить правильный указатель «выравнивания» в случае множественного наследования в C ++? - PullRequest
0 голосов
/ 30 декабря 2011

Скажем, у меня есть два интерфейса IFoo и IBar; плюс конкретный тип FooBar, реализующий эти интерфейсы:

class FooBar : public IFoo, public IBar
{
    //FooBar stuff
};

Где-то я получаю указатель void*, указывающий на экземпляр FooBar.

void* fooBar = getOrCreateStuff();

Теперь я хочу получить указатель на IBar из моего fooBar экземпляра.

IBar* iBar = static_cast< IBar* >(fooBar);

К сожалению, iBar не указывает на правильный адрес памяти. Пример глупый нарочно - в реальной жизни я не знаю конкретный тип, на который я указываю.

РЕДАКТИРОВАТЬ : Я пишу API, в котором я раскрываю метод template <class StuffT> StuffT getOrCreateStuff(). На данный момент нет абсолютно никакого способа узнать, какие типы разработчиков используют. Приведенный выше пример показывает вам, как этот метод должен использоваться. Мы регистрируем конкретный тип в API и возвращаем его как интерфейс. При работе с одиночным наследованием он работает как обаяние, но множественное наследование является более сложным.

Есть идеи, чтобы мой iBar указывал на смещение рабочего адреса?

Ответы [ 3 ]

4 голосов
/ 30 декабря 2011

Если вы не знаете, на что указываете, вам не повезло! С static_cast (v), где «v» имеет тип «void *», вы можете приводить к типу «T *» только в том случае, если «v» является результатом неявного преобразования в «void *». Если вы действительно получаете «void *», вам нужно сначала восстановить тип «B *» (например, некоторый базовый класс; он не должен быть общим базовым классом для всех ветвей, просто известно, что он присутствует). ) которая имеет хотя бы одну виртуальную функцию (например, деструктор, если там нет нужной вам функциональности), и оттуда вы можете использовать dynamic_cast (b) для восстановления некоторого типа где-нибудь в иерархии наследования. Обратите внимание, что даже это не обязательно работает, если в реальном объекте есть несколько подобъектов "T".

Причина, по которой все это необходимо, заключается в том, что в объекте, использующем множественное наследование, указатели на подобъекты корректируются: в зависимости от того, в какой ветке вы находитесь, может существовать один и тот же подобъект, а для работы с конкретным требуется другой указатель. Вы можете избежать использования dynamic_cast (b), но только если вы эффективно создадите свою собственную информационную систему времени выполнения.

1 голос
/ 30 декабря 2011

Измените getOrCreateStuff(), чтобы вернуть что-то отличное от void*.Если он возвращает IStuff*, а FooBar происходит от IStuff, тогда вы можете использовать dynamic_cast, чтобы получить IBar*.

0 голосов
/ 30 декабря 2011

, если вы уверены: «Где-то я получаю указатель void *, указывающий на экземпляр FooBar

тогда это решение:

IBar* iBar = static_cast<IBar*>(reinterpret_cast< FooBar* >(fooBar));

или:

IBar* iBar = dynamic_cast<IBar*>(reinterpret_cast< FooBar* >(fooBar));

Поскольку IBar - это интерфейс, он должен иметь чисто виртуальный метод, поэтому он полиморфный, поэтому можно использовать динамическое приведение.

...