(重新)实现dynamic_cast

时间:2012-03-23 12:40:31

标签: c++ embedded arm

我在ARM7嵌入式环境中工作。我使用的编译器不支持完整的C ++功能。它不支持的一个功能是动态类型转换。

有没有办法实施dynamic_cast<>()

我使用Google查找代码,但到目前为止还没有运气。有任何想法吗?有链接吗?

更新:

由于评论......我正在使用ARM(R)IAR C / C ++编译器。

4 个答案:

答案 0 :(得分:3)

dynamic_cast在离开基类时很有用,尽可能少地完成。

假设您想要执行此操作的实例是有限的,那么基类中的GetMessageType()等虚函数会在每个派生类中返回不同的值,这将让您知道static_cast的内容。

答案 1 :(得分:2)

看一下COM概念 - 对象有一个方法可以返回指向特定接口的指针,该接口由未编译到编译器中的标识符选择(在COM的情况下,是UUID)。

根据您的应用程序,可以使用简单的整数:

class castable {
    virtual bool cast_to(int desttype) = 0;
};

class type1 : public castable { public: static int const type = 1; };
class type2 : public castable { public: static int const type = 2; };

class impl : public type1, public type2 {
    virtual void *cast_to(int desttype) {
        switch(desttype) {
            case type1::type: return static_cast<type1 *>(this);
            case type2::type: return static_cast<type2 *>(this);
            default: return 0;
        }
    }
};

然后,如果模板正常工作:

template<typename T> T my_dynamic_cast(castable *obj) {
    return reinterpret_cast<T>(obj.cast_to(T::type));
}

然后,您可以正常创建对象,并在基类指针之间进行转换:

impl im;
type1 *t1 = &im;     // Implicit, as it is a base class
type2 *t2 = my_dynamic_cast<type2 *>(t1);

这里唯一的困难是分配标识符。

答案 2 :(得分:1)

这实际上取决于您需要多少dynamic_cast功能。

通常情况下,我看到dynamic_cast用于执行检查转化:如果最终dynamic_cast<Derived*>(p)实际类型不是0p将返回Derived*

......但即使这很复杂:

  • 如果p真的是EvenMoreDerived而不只是Derived怎么办?
  • 什么是p多次从Base继承?

它可以变得更加毛茸茸:

  • static_cast无法越过virtual继承边界。
  • static_cast不适合跨分支转换(您必须通过共同的祖先)
  • static_cast无法模拟dynamic_cast<void*>()转化。

因此,如果您希望在没有virtual的情况下进行单继承的情况下检查转换的简单准系统继承树,那么您实际上可以在用户域中实现它

否则,如果没有RTTI支持,您将会陷入困境。


简单(哑?)实现的示例,从类层次结构的支持开始:

class Base {
public:
  typedef size_t ID;

  virtual ID getID() const = 0;

protected:
  static ID NextID() { static ID = 0; return ID++; }

// much more stuff
};

class Derived: public Base {
public:
  static ID GetID() { static ID id = Base::NextID(); return id; }

  virtual ID getID() const { return GetID(); }
};

我们可以利用它:

template <typename To>
To* dyn_cast(Base* b) {
  if (b and b->getID() == To::GetID()) { return static_cast<To*>(b); }
  return 0;
}

但是,这仅适用于一个级别。因此,如果MoreDerived继承自Derived,那么:

MoreDerived md;
assert(dyn_cast<Derived>(&md)); // failure ...

所以这里真的很棘手。

一种可能的方法是从层次结构的顶部检查到底部。

class Base {
public:
  template <typename To>
  bool isa() const {
    return this->match(To::GetID());
  }

protected:
  typedef size_t ID;

  static ID NextID() { static ID id = 0; return id++; }

  virtual bool match(ID) const { return false; }
};

class Derived: public Base {
public:
  static ID GetID() { static ID id = NextID(); return id; }

protected:
  virtual bool match(ID id) const { return id == GetID() || Base::match(id); }
};

class MostDerived: public Derived {
public:
  static ID GetID() { static ID id = NextID(); return id; }

protected:
  virtual bool match(ID id) const { return id == GetID() || Derived::match(id); }
};

略微复杂,但现在:

template <typename To, typename From>
To const* dyn_cast(From const* f) {
  if (f and f->template isa<To>()) { return static_cast<To const*>(f); }
  return 0;
}

template <typename To, typename From>
To* dyn_cast(From* f) { return const_cast<To*>(dyn_cast<To>((From const*)f)); }

测试用例:

int main() {
  Derived derived; MostDerived mostDerived;
  Base* d = &derived, * md = &mostDerived;

  if (dyn_cast<Derived>(d)) { std::cout << "Derived -> Derived: ok\n"; }
  else                      { std::cout << "Derived -> Derived: ko\n"; }

  if (dyn_cast<MostDerived>(md)) { std::cout << "MostDerived -> MostDerived : ok\n"; }
  else                           { std::cout << "MostDerived -> MostDerived : ko\n"; }

  if (dyn_cast<Derived>(md)) { std::cout << "MostDerived -> Derived : ok\n"; }
  else                       { std::cout << "MostDerived -> Derived : ko\n"; }

  if (dyn_cast<MostDerived>(d)) { std::cout << "Derived -> MostDerived: ko\n"; }
  else                          { std::cout << "Derived -> MostDerived: ok\n"; }
}

In action at ideone

与真正的dynamic_cast相比,它仍然非常不完整。但它应该涵盖大多数用途。

答案 3 :(得分:-1)

是否有可能只是转换指针并开始将其用作其他类型的对象?

Foo* f = new Foo();
f.baz();
Bar* b = (Bar*)f;
b.bop();