trb*_*abb 18 c++ inheritance rtti typeid
有什么(如果有的话)c ++构造用于在运行时列出类的祖先?
基本上,我有一个类,它存储一个指向任何对象的指针,包括可能是一个原始类型(有点像boost::any
,我不想使用它,因为我需要保留我的对象的所有权).在内部,这个指针是一个void*
,但是这个类的目标是void*
用运行时类型安全包装.赋值运算符是模板化的,因此在赋值时我取出typeid()
传入指针并存储它.然后,当我稍后退回时,我可以检查typeid()
存储的类型type_info
.如果它不匹配,则演员将抛出异常.
但是有一个问题:我似乎失去了多态性.让我们说B
是一个基础D
.如果我将一个指针存储D
在我的类中,那么存储的type_info
也将是D
.然后,我可能想要检索一个B
指针.如果我使用我的类的方法来强制转换B*
,那么typeid(B) == typeid(D)
失败,并且D->B
转换会引发异常,即使转换是安全的.Dynamic_cast<>()
这里不适用,因为我是在一个void*
而不是一个B
或多个祖先的运作D
.
我希望能做的就是检查is_ancestor(typeid(B), typeid(D))
.这可能吗?(这不是dynamic_cast<>
在幕后做的吗?)
如果没有,那么我正在考虑采取第二种方法:实现一个类TypeInfo
,其派生类是模板化的单例.然后,我可以在这些类中存储我喜欢的任何信息,然后在我的AnyPointer
班级中保留指向它们的指针.这将允许我以更易于访问的方式在编译时生成/存储祖先信息.因此失败的选项#1(列出祖先的内置方式仅给出运行时可用的信息),是否有一个我可以使用的构造/过程,它将允许在编译时自动生成和存储祖先信息,最好没有不必明确输入的是"类A
派生自B
和C
; C
从导出D
等."?一旦我有这个,有没有一种安全的方式来实际执行该演员表?
Cas*_*eri 11
我有一个类似的问题,我通过例外解决了!我写了一篇关于此的文章:
http://drdobbs.com/cpp/229401004
好.继彼得的建议后,该想法的大纲如下.它依赖于以下事实:如果D
派生B
和D
抛出指针,B
则会激活期望指针的catch子句.
然后可以编写一个类(在我的文章中我称之为any_ptr
),其模板构造函数接受T*
并将其副本存储为void*
.该类实现了一种静态void*
转换为其原始类型T*
并抛出结果的机制.期望U*
where U
= T
或是U
其基础的catch子句T
将被激活,并且该策略是在原始问题中实现测试的关键.
编辑:( 由Matthieu M.提供答案是最好的自给自足,请参阅Dobbs博士的完整答案)
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;
}
};
Run Code Online (Sandbox Code Playgroud)
信息(通常)在实施中.虽然没有标准的C++方式来访问它,但它没有暴露出来.如果您愿意将自己绑定到特定的实现或实现集,您可以玩脏游戏来查找信息.
使用Itanium ABI的gcc示例如下:
#include <cassert>
#include <typeinfo>
#include <cxxabi.h>
#include <iostream>
bool is_ancestor(const std::type_info& a, const std::type_info& b);
namespace {
bool walk_tree(const __cxxabiv1::__si_class_type_info *si, const std::type_info& a) {
return si->__base_type == &a ? true : is_ancestor(a, *si->__base_type);
}
bool walk_tree(const __cxxabiv1::__vmi_class_type_info *mi, const std::type_info& a) {
for (unsigned int i = 0; i < mi->__base_count; ++i) {
if (is_ancestor(a, *mi->__base_info[i].__base_type))
return true;
}
return false;
}
}
bool is_ancestor(const std::type_info& a, const std::type_info& b) {
if (a==b)
return true;
const __cxxabiv1::__si_class_type_info *si = dynamic_cast<const __cxxabiv1::__si_class_type_info*>(&b);
if (si)
return walk_tree(si, a);
const __cxxabiv1::__vmi_class_type_info *mi = dynamic_cast<const __cxxabiv1::__vmi_class_type_info*>(&b);
if (mi)
return walk_tree(mi, a);
return false;
}
struct foo {};
struct bar : foo {};
struct baz {};
struct crazy : virtual foo, virtual bar, virtual baz {};
int main() {
std::cout << is_ancestor(typeid(foo), typeid(bar)) << "\n";
std::cout << is_ancestor(typeid(foo), typeid(baz)) << "\n";
std::cout << is_ancestor(typeid(foo), typeid(int)) << "\n";
std::cout << is_ancestor(typeid(foo), typeid(crazy)) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
我将其type_info
转换为内部使用的实际类型,然后递归地使用它来遍历继承树.
我不建议在实际代码中执行此操作,但作为实现细节的练习,这并非不可能.
归档时间: |
|
查看次数: |
1819 次 |
最近记录: |