如何检查对象的types是否是C ++中的特定子类?
我正在考虑使用typeid()
但是我不知道如何判断这个types是否是另一个类的子类(顺便说一句,这是抽象的)
你真的不应该。 如果你的程序需要知道一个对象是什么类,那通常表明一个devise缺陷。 看看你是否可以使用虚拟function得到你想要的行为。 此外,有关您正在尝试做什么的更多信息将有所帮助。
我假设你有这样的情况:
class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
如果这是你有什么,然后尝试做这样的事情:
class Base { virtual void bar() = 0; }; class A : public Base { void bar() {/* do X */} }; class B : public Base { void bar() {/* do Y */} }; void foo(Base *p) { p->bar(); }
编辑:由于关于这个答案的辩论在这么多年以后仍然继续,我想我应该引用一些参考。 如果你有一个基类的指针或引用,并且你的代码需要知道该对象的派生类,那么它违反了Liskovreplace原则 。 Bob叔叔把这称为“ 面向对象devise的诅咒 ”。
class Base { public: virtual ~Base() {} }; class D1: public Base {}; class D2: public Base {}; int main(int argc,char* argv[]); { D1 d1; D2 d2; Base* x = (argc > 2)?&d1:&d2; if (dynamic_cast<D2*>(x) == nullptr) { std::cout << "NOT A D2" << std::endl; } if (dynamic_cast<D1*>(x) == nullptr) { std::cout << "NOT A D1" << std::endl; } }
你可以用dynamic_cast
(至less对于多态types)来完成。
其实,第二个想法 – 你不能确定它是否是一个特定的dynamic_cast
types – 但你可以告诉它是否是该types或其任何子类。
template <class DstType, class SrcType> bool IsType(const SrcType* src) { return dynamic_cast<const DstType*>(src) != nullptr; }
dynamic_cast
可以确定types是否包含inheritance层次结构中任何位置的目标types(是的,这是一个鲜为人知的特性,如果B
inheritance自A
和C
,它可以将A*
直接转换为C*
)。 typeid()
可以确定对象的确切types。 但是,这些都应该非常谨慎地使用。 正如已经提到的,你应该总是避免dynamictypes识别,因为它表明了一个devise缺陷。 (另外,如果你知道对象是确定的目标types的话,你可以用static_cast
做一个downcast,Boost提供了一个polymorphic_downcast
,它将在debugging模式下执行dynamic_cast
的downcast,在release模式下它将会使用一个static_cast
)。
我不同意你不应该在C ++中检查对象的types。 如果你能避免它,我同意你应该。 说你永远不应该在任何情况下这样做太过分了。 你可以用很多种语言来做到这一点,它可以让你的生活变得更轻松。 例如,Howard Pinsley向我们展示了他在C#中的职位。
我在Qt框架上做了很多工作。 一般来说,我以他们的方式做事(至less在他们的框架中工作的时候)的模式。 QObject类是所有Qt对象的基类。 该类具有函数isWidgetType()和isWindowType()作为快速子类检查。 那么,为什么不能检查你自己的派生类,它的性质是可比的呢? 这里是一些其他职位的QObject分拆:
class MyQObject : public QObject { public: MyQObject( QObject *parent = 0 ) : QObject( parent ){} ~MyQObject(){} static bool isThisType( const QObject *qObj ) { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); } };
然后当你传递一个指向QObject的指针时,你可以通过调用静态成员函数来检查它是否指向派生类:
if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
我不知道我是否正确地理解你的问题,所以让我用我自己的话来重述它。
问题:给定类B
和D
,确定D
是否是B
的子类(反之亦然?)
解决scheme:使用一些模板魔法! 好的,你要看看LOKI这个由传奇C ++作者Andrei Alexandrescu制作的优秀的模板元编程库。
更具体地说,下载LOKI并在源代码中包含TypeManip.h
头TypeManip.h
,然后使用SuperSubclass
类模板,如下所示:
if(SuperSubClass<B,D>::value) { ... }
根据文档,如果B
是D
的公共基础,或者B
和D
是相同types的别名,则SuperSubClass<B,D>::value
将为真。
即D
或B
一个子类或D
与B
相同。
我希望这有帮助。
编辑:
请注意SuperSubClass<B,D>::value
发生在编译时,与使用dynamic_cast
某些方法不同,因此在运行时使用此系统没有任何损失。
在C#中,你可以简单地说:
if (myObj is Car) { }
#include <stdio.h> #include <iostream.h> class Base { public: virtual ~Base() {} template<typename T> bool isA() { return (dynamic_cast<T*>(this) != NULL); } }; class D1: public Base {}; class D2: public Base {}; class D22: public D2 {}; int main(int argc,char* argv[]); { D1* d1 = new D1(); D2* d2 = new D2(); D22* d22 = new D22(); Base* x = d22; if( x->isA<D22>() ) { std::cout << "IS A D22" << std::endl; } if( x->isA<D2>() ) { std::cout << "IS A D2" << std::endl; } if( x->isA<D1>() ) { std::cout << "IS A D1" << std::endl; } if(x->isA<Base>() ) { std::cout << "IS A Base" << std::endl; } }
结果:
IS A D22 IS A D2 IS A Base
你只能在编译时使用模板,除非你使用RTTI。
它可以让你使用typeid函数,它会产生一个指向包含types信息的type_info结构的指针。
在维基百科上阅读
我正在考虑使用
typeid()
…
那么,是的,它可以通过比较: typeid().name()
。 如果我们采取已经描述的情况,那么:
class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
foo(Base *p)
一个可能的实现是:
#include <typeinfo> void foo(Base *p) { if(typeid(*p) == typeid(A)) { // the pointer is pointing to the derived class A } else if (typeid(*p).name() == typeid(B).name()) { // the pointer is pointing to the derived class B } }