C++ C++;-不使用RTTI/dynamic_cast向下投射菱形继承对象

C++ C++;-不使用RTTI/dynamic_cast向下投射菱形继承对象,c++,casting,multiple-inheritance,rtti,diamond-problem,C++,Casting,Multiple Inheritance,Rtti,Diamond Problem,我目前正在集成一个第三方软件包,该软件包在非RTTI平台(Android)上使用大量RTTI内容。基本上,我做了自己的RTTI实现,但我遇到了一个问题 问题是很多类都存在菱形继承问题,因为所有类都派生自同一基类(对象)。。因此,如果我想从基类向下转换到派生类,我必须使用动态转换,但是RTTI不可用!当存在没有动态强制转换的虚拟继承时,如何将对象从父对象转换为子对象 看起来是这样的: class A { public: virtual char* func() { return "A"; };

我目前正在集成一个第三方软件包,该软件包在非RTTI平台(Android)上使用大量RTTI内容。基本上,我做了自己的RTTI实现,但我遇到了一个问题

问题是很多类都存在菱形继承问题,因为所有类都派生自同一基类(对象)。。因此,如果我想从基类向下转换到派生类,我必须使用动态转换,但是RTTI不可用!当存在没有动态强制转换的虚拟继承时,如何将对象从父对象转换为子对象

看起来是这样的:

class A 
{
public:
 virtual char* func() { return "A"; };
};
class B : public virtual A
{
public:
 //virtual char* func() { return "B"; };
};
class C : public virtual A 
{
public:
 //virtual char* func() { return "C"; };
};

class D : public B, public C 
{
public:
 //virtual char* func() { return "D"; };
};

D d;
A* pa = static_cast<A*>(&d);
D* pd = static_cast<D*>(pa); // can't do that! dynamic_cast does work though...
A类
{
公众:
虚拟字符*func(){返回“A”;};
};
B类:公共虚拟A
{
公众:
//虚拟字符*func(){返回“B”;};
};
C类:公共虚拟A
{
公众:
//虚拟字符*func(){return“C”;};
};
D类:公共B、公共C
{
公众:
//虚拟字符*func(){return“D”;};
};
D;
A*pa=静态施法(&d);
D*pd=静态(pa);//不能那样做!不过,动态_cast确实有效。。。
这些是我的错误:

错误C2635:无法将“a*”转换为“D*”;隐含了从虚拟基类的转换

错误C2440:“正在初始化”:无法从“test\u convert::A*”转换为“test\u convert::D*” 从基础转换为派生需要动态转换或静态转换


有什么想法吗?

您只能使用
动态_cast
进行此转换;没有其他演员会这么做

如果您无法设计接口,从而不需要执行这种类型的强制转换,那么您唯一可以做的就是将强制转换功能作为类层次结构的一部分

例如(非常粗糙)


只要您有另一种方法来确保您所做的操作在运行时是类型安全的,就可以使用reinterpret_cast


它基本上与C样式转换相同,因此只有在必要时才使用它,但它允许编译上面的代码。

在大多数情况下,可以使用访问者模式来避免降级。它也可以用来避免动态施法

一些警告:

1) 必须能够更改有问题的类别。
2) 您可能需要了解每个派生类。
3) 必须知道对象至少派生自基类,否则不能尝试强制转换完全不相关的类型。(这似乎实现了:“我想从基类向下转换到派生类”)

在下面的示例中,我使用了模板。这些可以很容易摆脱,但需要相当多的写作努力

class A;
class B;
class C;
class D;

// completely abstract Visitor-baseclass.
// each visit-method must return whether it handled the object
class Visitor
{ 
public:
    virtual bool visit(A&) = 0;
    virtual bool visit(B&) = 0;
    virtual bool visit(C&) = 0;
    virtual bool visit(D&) = 0;
};

class A
{
public:
    virtual const char* func() { return "A"; };
    virtual void accept(Visitor& visitor) { visitor.visit(*this); }
};
class B : public virtual A
{
public:
    virtual const char* func() { return "B"; };
    virtual void accept(Visitor& visitor) { visitor.visit(*this); }
};
class C : public virtual A
{
public:
    virtual const char* func() { return "C"; };
    virtual void accept(Visitor& visitor) { visitor.visit(*this); }
};
class D : public B, public C
{
public:
    virtual const char* func() { return "D"; };
    virtual void accept(Visitor& visitor) { visitor.visit(*this); }
};

// implementation-superclass for visitors: 
// each visit-method is implemented and calls the visit-method with the parent-type(s)
class InheritanceVisitor : public Visitor
{ 
    virtual bool visit(A& a) { return false; }
    virtual bool visit(B& b) { return visit(static_cast<A&>(b)); }
    virtual bool visit(C& c) { return visit(static_cast<A&>(c)); }
    virtual bool visit(D& d) { return visit(static_cast<B&>(d)) || visit(static_cast<C&>(d)); }
};

template<typename T> // T must derive from A
class DerivedCastVisitor : public InheritanceVisitor
{
public:
    DerivedCastVisitor(T*& casted) : m_casted(casted) {}
    virtual bool visit(T& t) 
    { m_casted = &t; return true; }
private:
    T*& m_casted;
};

// If obj is derived from type T, then obj is casted to T* and returned. 
// Else NULL is returned.
template<typename T> 
T* derived_cast(A* obj)
{
  T* t = NULL;
  if (obj) 
  {
    DerivedCastVisitor<T> visitor(t);
    obj->accept(visitor);
  }
  return t;
}

int main(int argc, char** argv)
{
  std::auto_ptr<A> a(new A);
  std::auto_ptr<A> b(new B);
  std::auto_ptr<A> c(new C);
  std::auto_ptr<A> d(new D);

  assert(derived_cast<A>(a.get()) != NULL); // a has exact type A
  assert(derived_cast<B>(b.get()) != NULL); // b has exact type B
  assert(derived_cast<A>(b.get()) != NULL); // b is derived of A
  assert(derived_cast<C>(b.get()) == NULL); // b is not derived of C
  assert(derived_cast<D>(d.get()) != NULL); // d has exact type D
  assert(derived_cast<B>(d.get()) != NULL); // d is derived of B 
  assert(derived_cast<C>(d.get()) != NULL); // d is derived of C, too
  assert(derived_cast<D>(c.get()) == NULL); // c is not derived of D

  return 0;
}
A类;
乙级;;
丙级;;
D类;
//完全抽象的访问者基类。
//每个visit方法必须返回它是否处理了对象
班级访客
{ 
公众:
虚拟布尔访问(A&)=0;
虚拟布尔访问(B&)=0;
虚拟布尔访问(C&)=0;
虚拟布尔访问(D&)=0;
};
甲级
{
公众:
虚常量char*func(){返回“A”;};
虚拟无效接受(访问者和访问者){Visitor.visit(*this);}
};
B类:公共虚拟A
{
公众:
虚常量char*func(){返回“B”;};
虚拟无效接受(访问者和访问者){Visitor.visit(*this);}
};
C类:公共虚拟A
{
公众:
虚常量char*func(){返回“C”;};
虚拟无效接受(访问者和访问者){Visitor.visit(*this);}
};
D类:公共B、公共C
{
公众:
虚常量char*func(){返回“D”;};
虚拟无效接受(访问者和访问者){Visitor.visit(*this);}
};
//访问者的实现超类:
//实现每个访问方法,并使用父类型调用访问方法
类继承访问者:公共访问者
{ 
虚拟布尔访问(A&A){return false;}
虚拟布尔访问(B&B){回访(静态_cast(B));}
虚拟布尔访问(C&C){回访(静态_cast(C));}
虚拟布尔访问(D&D){回访(静态播放(D))| |访问(静态播放(D))}
};
模板//T必须从
类DerivedCastVisitor:公共继承Visitor
{
公众:
DerivedCastVisitor(T*&casted):m_casted(casted){}
虚拟布尔访问(T&T)
{m_casted=&t;返回true;}
私人:
T*&m_铸造;
};
//如果obj是从类型T派生的,则obj被强制转换为T*并返回。
//否则返回NULL。
模板
T*派生型(A*obj)
{
T*T=NULL;
如果(obj)
{
游客(t);
obj->接受(访客);
}
返回t;
}
int main(int argc,字符**argv)
{
标准:自动测试a(新a);
标准:自动测试b(新b);
标准:自动测试c(新c);
标准::自动测试d(新d);
assert(派生的_cast(a.get())!=NULL);//a具有完全相同的类型a
assert(派生的_-cast(b.get())!=NULL);//b具有确切的类型b
assert(派生的_cast(b.get())!=NULL);//b是从A派生的
assert(派生的_cast(b.get())==NULL);//b不是从C派生的
assert(派生的_cast(d.get())!=NULL);//d具有确切的类型d
assert(派生的_cast(d.get())!=NULL);//d派生自B
assert(派生的_cast(d.get())!=NULL);//d也是从C派生的
assert(派生的_cast(c.get())==NULL);//c不是从D派生的
返回0;
}

虚拟继承的问题是基类地址不一定是 与派生地址相同。因此,即使是
reinterpret\u cast
void*
cast也会 没有帮助

不使用
dynamic_cast
解决此问题的一种方法是计算指针类型(精确类型和ref类型)之间的偏移量,以便在cast期间相应地修改对象地址

 template <typename E, typename T>
 E& force_exact(const T& ref)
 {
   static const E* exact_obj;
   static const T& exact_obj_ref = *exact_obj;
   static const ptrdiff_t exact_offset =
     (const char*)(void*)(&exact_obj_ref)
     - (const char*)(void*)(exact_obj);
   return *(E*)((char*)(&ref) - exact_offset);
 }
模板
E&force_精确(常数T&ref)
{
静态常数*精确对象;
静态常数T&exact_obj_ref=*exact_obj;
静态常数ptrdiff t精确偏移量=
(常量字符*)(无效*)(&精确对象参考)
-(常量字符*)(无效*)(精确对象);
返回*(E*)((char*)(&ref)-精确的偏移量);
}
代码:

template <typename E, typename T>
E& force_exact(const T& ref)
 {
   static const E* exact_obj;
   static const T& exact_obj_ref = *exact_obj;
   static const ptrdiff_t exact_offset = ...
在MSVC 2008、WinXP 32b下测试

欢迎提出任何意见/更好的解决方案

LuP

Android<
template <typename E, typename T>
E& force_exact(const T& ref)
 {
   static const E* exact_obj;
   static const T& exact_obj_ref = *exact_obj;
   static const ptrdiff_t exact_offset = ...
template <typename D, typename B>
D & Cast2Derived(B & b)
{ static D d;
  static D * pD = & d;
  static B * pB = pD;
  static ptrdiff_t off = (char *) pB - (char *) pD;

  return * (D *) ((char *) & b - off);
}