Приведение производного класса к одной из баз через указатель базы

РЕДАКТИРОВАТЬ: Хорошо, как я вижу сейчас, это сильно меняет дело, поэтому более точный сценарий таков:

Иерархия, которая у меня сейчас есть, похожа на эту:

class IBase() { virtual void Foo() = 0; };

class Base() : public IBase { virtual void Foo() { } };

class IDerived() { virtual void Bar() = 0; };

template<typename TT, typename TB, typename... TI>
class Derived : public Base, public IDerived { virtual void Bar() {}};

template<typename TT, typename TB, typename... TI>
IBase* CreateDerived() { return new Derived(); }

IBase* derived = CreateDerived<some types...>();

Я получаю сообщение об ошибке с Visual Studio при попытке привести объект и вызвать функцию:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.

Все вызовы интерфейса IBase через производные работают нормально, но когда я пытаюсь привести производные к IDerived, я получаю сообщение об ошибке при вызове любой функции:

IDerived* d = (IDerived*)derived;
d->Bar(); <- boom error ;)

Я предполагаю, что такое приведение является недопустимым, но как я могу привести указатель, чтобы я мог получить доступ к методам интерфейса IDerived (предпочтительно без dynamic_cast, я бы предпочел хороший и переносимый хак, если таковой существует;))? Можно ли как-то рассчитать смещение указателя, чтобы использовать правильный vtable и все работает как надо?

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

РЕДАКТИРОВАТЬ: Теперь, как вы можете видеть, это становится сложно и сложно. Я не знаю точный тип производного, который я получаю, поскольку он шаблонизирован, также функция CreateDerived является шаблонной и возвращает интерфейс.

Также одно из требований — не использовать dynamic_cast (RTTI отключен в проекте).

3

Решение

Вы выполняете перекрестный бросок; IBase а также IDerived не связаны. Вы должны бросить на Derived сначала, а потом IDerived, Если вы использовали static_cast а не C-бросок, компилятор поймал бы это для вас во время компиляции.

Я полагаю, вы знаете, что IBase действительно Derived потому что вы использовали C бросок, но если вы этого не сделаете, вы также можете использовать dynamic_cast безопасно выполнять перекрестные броски.

РЕДАКТИРОВАТЬ: Если вы не можете использовать RTTI и вы не знаете динамический тип объекта, то виртуальное наследование и dynamic_cast выйти из окна. Когда вы звоните CreateDerived похоже, вы знаете динамический тип объекта (из-за его аргументов шаблона), так что вы можете иметь std::map<IBase*, IDerived*> а затем после CreateDerived<TT, TB, TI...>() позвонить можно static_cast IBase* в Derived<TT, TB, TI...>* а затем вставьте указатель как ключ и значение в карту.

Просто включите RTTI; это становится сложным. >.<

РЕДАКТИРОВАТЬ 2: В качестве альтернативы, вы, кажется, знаете, что объект, на который указывает IBase* также вытекает из IDerived*, Если вы можете изменить иерархию классов, у вас может быть абстрактный базовый класс, производный от обоих IBase а также IDerived а затем есть Derived происходят из этого нового базового класса. Тогда ты можешь static_cast из IBase* в новый класс в иерархии, а затем IDerived*,

Это будет выглядеть примерно так:

class IBase { virtual void Foo() = 0; };

class Base : public IBase { virtual void Foo() { } };

class IDerived { virtual void Bar() = 0; };

class BaseAndDerived : public Base, public IDerived { };

template<typename TT, typename TB, typename... TI>
class Derived : public BaseAndDerived { virtual void Bar() {}};
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]