我一直在思考使用的方式,typeid()
但是我不知道如何问该类型是否是另一个类的子类(顺便说一句,它是抽象的)
Answers:
你真的不应该。如果您的程序需要知道对象是什么类,则通常表明存在设计缺陷。查看是否可以使用虚拟函数获得所需的行为。此外,有关您尝试执行的操作的更多信息也会有所帮助。
我假设您遇到这样的情况:
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();
}
编辑:由于关于这个答案的争论已经进行了很多年,所以我认为我应该提出一些参考。如果您有一个指向基类的指针或引用,并且您的代码需要知道该对象的派生类,则它违反了Liskov替换原理。鲍伯叔叔将此称为“面向对象设计的厌恶品”。
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<>
这里吗?还static_cast<>
不够吗?
x
在编译时告诉类型吗?如果是这样,那static_cast<>()
将工作。如果您x
直到运行时才能知道类型,那么您需要dynamic_cast<>()
您可以使用它dynamic_cast
(至少对于多态类型)。
实际上,经过深思熟虑-您无法确定它是否是特定类型-但dynamic_cast
可以确定它是否是该类型或其任何子类。
template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
return dynamic_cast<const DstType*>(src) != nullptr;
}
std::is_polymorphic_v<T>
是false
。
下面的代码演示了3种不同的方法:
#include <iostream>
#include <typeinfo>
#include <typeindex>
enum class Type {Base, A, B};
class Base {
public:
virtual ~Base() = default;
virtual Type type() const {
return Type::Base;
}
};
class A : public Base {
Type type() const override {
return Type::A;
}
};
class B : public Base {
Type type() const override {
return Type::B;
}
};
int main()
{
const char *typemsg;
A a;
B b;
Base *base = &a; // = &b; !!!!!!!!!!!!!!!!!
Base &bbb = *base;
// below you can replace base with &bbb and get the same results
// USING virtual function
// ======================
// classes need to be in your control
switch(base->type()) {
case Type::A:
typemsg = "type A";
break;
case Type::B:
typemsg = "type B";
break;
default:
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
// USING typeid
// ======================
// needs RTTI. under gcc, avoid -fno-rtti
std::type_index ti(typeid(*base));
if (ti == std::type_index(typeid(A))) {
typemsg = "type A";
} else if (ti == std::type_index(typeid(B))) {
typemsg = "type B";
} else {
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
// USING dynamic_cast
// ======================
// needs RTTI. under gcc, avoid -fno-rtti
if (dynamic_cast</*const*/ A*>(base)) {
typemsg = "type A";
} else if (dynamic_cast</*const*/ B*>(base)) {
typemsg = "type B";
} else {
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
}
上面的程序打印此:
type A
type A
type A
我不同意您永远不应该在C ++中检查对象的类型。如果您可以避免,我同意您应该这样做。说无论如何在任何情况下都不要这样做,这太过分了。您可以使用多种语言来完成此操作,这可以使您的生活更加轻松。例如,霍华德·平斯利(Howard Pinsley)在他关于C#的帖子中向我们展示了如何。
我在Qt Framework上做了很多工作。通常,我会按照他们的工作方式(至少在他们的框架中工作时)对我的工作进行建模。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
(反之亦然?)
解决方案:使用一些模板魔术!好的,真的,您需要看一下LOKI,这是由传说中的C ++作者Andrei Alexandrescu制作的出色的模板元编程库。
更具体地说,下载LOKI并将其标头包含TypeManip.h
在源代码中,然后SuperSubclass
按如下方式使用类模板:
if(SuperSubClass<B,D>::value)
{
...
}
根据文档,SuperSubClass<B,D>::value
如果B
是的公共基础D
,或者如果B
和D
是相同类型的别名,则为true 。
即D
是的子类B
或D
与相同B
。
我希望这有帮助。
编辑:
请注意,SuperSubClass<B,D>::value
与某些使用的方法不同,在编译时评估发生的情况dynamic_cast
,因此在运行时使用该系统不会有任何损失。
#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
在C#中,您可以简单地说:
if (myObj is Car) {
}
我一直在考虑使用
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
}
}
std::is_base_of
无法按需工作。:3