Check for derived type (C++)
How do I check at runtime if an object is of type ClassA or of derived type ClassB? In one case I have to handle both instances separately
ClassA* SomeClass::doSomething ( ClassA* )
{
if( /* parameter is of type base class */) {
} else if { /* derived class */ ) {
}
}
Maybe I cou开发者_运维技巧ld say that the derived class ClassB has some special capabilities. But how do I do that without changing the existing class ClassA ?
It's generally a very bad idea to switch on the exact type like that. By doing this, you are tightly coupling your method to derived classes of ClassA
. You should use polymorphism. Introduce a virtual
method in class A, override it in class B and simply call it in your method.
Even if I was forced to handle the functionality in the external function itself for some reason, I would do something like:
class ClassA {
public: virtual bool hasSpecificFunctionality() { return false; }
};
class ClassB : public ClassA {
public: virtual bool hasSpecificFunctionality() { return true; }
};
ClassA* SomeClass::doSomething ( ClassA* arg )
{
if (arg->hasSpecificFunctionality()) {
} else {
}
}
Use a dynamic_cast
as follows:
ClassA* SomeClass::doSomething(ClassA* a)
{
if (dynamic_cast<DerivedClass*>(a)) {
...
} else if (dynamic_cast<BaseClass*>(a)) {
...
}
}
dynamic_cast<T *>(ptr)
will return 0
in case ptr
is not a pointer of type T
, and will return a pointer of type T
otherwise.
dynamic_cast
can usually be avoided and is an indicator of bad design / code. If you can avoid it, try to do so, as it requires RTTI in your final executable.
Others have pointed out that switching on types is usually a bad idea, so I won't. If you really have to do it, you can use the typeid
operator to switch on the dynamic type of an object:
ClassA* SomeClass::doSomething ( ClassA* a )
{
if (typeid(*a) == typeid(ClassA)) {
/* parameter is of type base class */
} else if (typeid(*a) == typeid(ClassB)) {
/* a specific derived class */
} else {
/* some other derived class */
}
}
dynamic_cast
is similar, but tests for convertibility, not equality:
ClassA* SomeClass::doSomething ( ClassA* a )
{
if (ClassB *b = dynamic_cast<classB*>(a)) {
/* parameter is, or is derived from, ClassB */
} else {
/* parameter is, or is derived from, ClassA but not ClassB */
}
}
These only work if ClassA
is polymorphic (that is, it has at least one virtual function).
Why not have a doSomething() method on ClassB that handles ClassB's extra capabilities? This is the essence of polymorphism.
The syntax is this:
ClassA* SomeClass::doSomething ( ClassA* pa )
{
ClassB* pb = dynamic_cast<ClassB*>(pa);
if( pb ) ...
(Note that this only works within polymorphic class hierarchies. That is, there have to be virtual functions involved.)
However, you should try to avoid that. What do you need it for that cannot be solved by applying virtual functions?
Slighlty different that what you asked for
ClassB* b;
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) {
// not a classB*
} else {
// a classB* in b
}
精彩评论