使用RTTI确定C ++中的继承图? [英] Using RTTI to determine inheritance graph in C++?

查看:102
本文介绍了使用RTTI确定C ++中的继承图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么,如果有的话,c ++结构是否有在运行时列出类的祖先?

What, if any, c++ constructs are there for listing the ancestors of a class at runtime?

基本上,我有一个类存储指向任何对象的指针,包括可能的原始类型(有点像 boost :: any ,我不想使用,因为我需要保留我的对象的所有权)。在内部,这个指针是一个 void * ,但这个类的目标是用运行时类型包装 void * -安全。赋值运算符是模板化的,因此在赋值时,我使用传入指针的 typeid()并存储它。然后当我回来后,我可以检查铸造类型的 typeid()对存储的 type_info 。如果它不匹配,转换会抛出异常。

Basically, I have a class which stores a pointer to any object, including possibly a primitive type (somewhat like boost::any, which I don't want to use because I need to retain ownership of my objects). Internally, this pointer is a void*, but the goal of this class is to wrap the void* with runtime type-safety. The assignment operator is templated, so at assignment time I take the typeid() of the incoming pointer and store it. Then when I cast back later, I can check the typeid() of the cast type against the stored type_info. If it mismatches, the cast will throw an exception.

但有一个问题:看起来我失去了多态性。让我们说 B D 的基础。如果我在我的类中存储了一个 D 的指针,那么存储的 type_info 也将是 D 。然后稍后,我可能想要检索 B 指针。如果我使用我的类的方法转换为 B * ,那么 typeid(B)== typeid(D)失败,并且转换提出了异常,即使 D-> B 转换是安全的。 Dynamic_cast<>()不适用于这里,因为我在 void * B D 的祖先。

But there's a problem: It seems I lose polymorphism. Let's say B is a base of D. If I store a pointer to D in my class, then the stored type_info will also be of D. Then later on, I might want to retrieve a B pointer. If I use my class's method to cast to B*, then typeid(B) == typeid(D) fails, and the cast raises an exception, even though D->B conversion is safe. Dynamic_cast<>() doesn't apply here, since I'm operating on a void* and not an ancestor of B or D.

我想要做的是检查 is_ancestor(typeid(B),typeid(D))这是否可能? dynamic_cast 是在幕后做的吗?)

What I would like to be able to do is check is_ancestor(typeid(B), typeid(D)). Is this possible? (And isn't this what dynamic_cast<> is doing behind the scenes?)

如果没有,那么我正在考虑采取第二种方法:实现一个类 TypeInfo ,其派生类是模板单例。然后我可以存储任何我喜欢的信息在这些类,然后在我的 AnyPointer 类中保留指针。这将允许我以更容易访问的方式在编译时生成/存储祖先信息。因此,失败的选项#1(列出祖先的内置方式只给出在运行时可用的信息),是否有一个可以使用的构造/过程,它将允许祖先信息在编译时自动生成和存储,必须明确输入 源自 B C ; C 派生自 D 等?一旦我有这个,是否有一个安全的方式来实际执行这个演员?

If not, then I am thinking of taking a second approach anyway: implement a a class TypeInfo, whose derived classes are templated singletons. I can then store whatever information I like in these classes, and then keep pointers to them in my AnyPointer class. This would allow me to generate/store the ancestor information at compile time in a more accessible way. So failing option #1 (a built-in way of listing ancestors given only information available at runtime), is there a construct/procedure I can use which will allow the ancestor information to be generated and stored automatically at compile-time, preferably without having to explicitly input that "class A derives from B and C; C derives from D" etc.? Once I have this, is there a safe way to actually perform that cast?

推荐答案

我有一个类似的问题,我通过异常解决了!我写了一篇文章:

I had a similar problem which I solved through exceptions! I wrote an article about that:

http:// drdobbs .com / cpp / 229401004

好的。按照彼得的建议,这个想法的大纲如下。它依赖于以下事实:如果 D 源自 B 以及指向 D 被抛出,则一个catch子句期望指向 B 的指针将被激活。

Ok. Following Peter's advise the outline of the idea follows. It relies on the fact that if D derives from B and a pointer to D is thrown, then a catch clause expecting a pointer to B will be activated.

然后可以写一个类(在我的文章中,我调用它 any_ptr ),其模板构造函数接受 T * 将它的副本存储为 void * 。类实现了一种机制,静态地将 void * 转换为其原始类型 T * 并抛出结果。 catch子句期望 U * 其中 U = T U 是基础的 T 将被激活,这个策略是实现测试的关键, 。

One can then write a class (in my article I've called it any_ptr) whose template constructor accepts a T* and stores a copy of it as a void*. The class implements a mechanism that statically cast the void* to its original type T* and throws the result. A catch clause expecting U* where U = T or U is a base of T will be activated and this strategy is the key to implementing a test as in the original question.

编辑(由Matthieu M.提供的答案是最好的自包含,请参考Dobbs博士的完整答案)

(by Matthieu M. for answers are best self-contained, please refer to Dr Dobbs for the full answer)

class any_ptr {

    void* ptr_;
    void (*thr_)(void*);

    template <typename T>
    static void thrower(void* ptr) { throw static_cast<T*>(ptr); }

public:

    template <typename T>
    any_ptr(T* ptr) : ptr_(ptr), thr_(&thrower<T>) {}

    template <typename U>
    U* cast() const {
        try { thr_(ptr_); }
        catch (U* ptr) { return ptr; }
        catch (...) {}
        return 0;
    }
};

这篇关于使用RTTI确定C ++中的继承图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆