编辑:好的,正如我现在看到的那样,这种情况发生了很大变化,所以更精确的情况就是如此:
我目前拥有的层次结构与此类似:
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...>();
我在尝试转换对象并调用函数时遇到错误:
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并且一切正常吗?
我编程已经有很长一段时间了,但我总是躲过所有那些对有大量接口和模板的工程系统的幻想,现在我注定要自己制作一个。
编辑:现在你可以看到这变得棘手和困难。我不知道我得到的Derived的确切类型,因为它是模板化的,函数CreateDerived也是模板化的并返回接口。此外,其中一个要求是不使用dynamic_cast(在项目中禁用RTTI)
答案 0 :(得分:1)
你正在进行交叉投射; IBase
和IDerived
无关。您需要先转换为Derived
,然后转换为IDerived
。如果你使用static_cast
而不是C cast,编译器会在编译时为你捕获这个。
我假设您知道IBase
实际上是Derived
,因为您使用的是C版,但如果不这样做,那么您也可以使用dynamic_cast
执行交叉投射安全。
编辑:如果你不能使用RTTI并且你不知道对象的动态类型,那么虚拟继承和dynamic_cast
就会消失。当您调用CreateDerived
时,您似乎知道对象的动态类型(因为它的模板参数),因此您可以拥有std::map<IBase*, IDerived*>
,然后在CreateDerived<TT, TB, TI...>()
调用后可以{ {1}} static_cast
到IBase*
,然后将指针作为键和值插入到地图中。
启用RTTI;这变得复杂了。 &GT;。&LT;
编辑2:或者,您似乎知道Derived<TT, TB, TI...>*
指向的对象也来自IBase*
。如果您可以修改类层次结构,则可以使用从IDerived*
和IBase
派生的抽象基类,然后从此新基类派生IDerived
。然后,您可以Derived
从static_cast
到层次结构中的新类,然后转到IBase*
。
它看起来像这样:
IDerived*