通过基指针将派生类强制转换为其中一个基类

时间:2013-09-13 10:27:30

标签: c++ inheritance upcasting

编辑:好的,正如我现在看到的那样,这种情况发生了很大变化,所以更精确的情况就是如此:

我目前拥有的层次结构与此类似:

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)

1 个答案:

答案 0 :(得分:1)

你正在进行交叉投射; IBaseIDerived无关。您需要先转换为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_castIBase*,然后将指针作为键和值插入到地图中。

启用RTTI;这变得复杂了。 &GT;。&LT;

编辑2:或者,您似乎知道Derived<TT, TB, TI...>*指向的对象也来自IBase*。如果您可以修改类层次结构,则可以使用从IDerived*IBase派生的抽象基类,然后从此新基类派生IDerived。然后,您可以Derivedstatic_cast到层次结构中的新类,然后转到IBase*

它看起来像这样:

IDerived*