Как я проверяю во времени выполнения, если объект имеет тип ClassA или производного типа ClassB? В одном случае я должен обработать оба экземпляра отдельно
ClassA* SomeClass::doSomething ( ClassA* )
{
if( /* parameter is of type base class */) {
} else if { /* derived class */ ) {
}
}
Возможно, я мог сказать, что производный класс ClassB имеет некоторые специальные возможности. Но как я делаю это, не изменяя существующий класс ClassA?
Обычно очень плохая идея включать именно такой тип. Делая это, вы тесно связываете свой метод с производными классами ClassA
. Вам следует использовать полиморфизм. Внесите виртуальный
метод в класс A, переопределите его в классе B и просто вызовите его в своем методе.
Даже если бы я был по какой-то причине вынужден обрабатывать функциональность самой внешней функции, я бы сделал что-то вроде:
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 {
}
}
Почему бы не иметь в ClassB метод doSomething (), который обрабатывает дополнительные возможности ClassB? В этом суть полиморфизма.
Немного отличается от того, что вы просили
ClassB* b;
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) {
// not a classB*
} else {
// a classB* in b
}
Синтаксис следующий:
ClassA* SomeClass::doSomething ( ClassA* pa )
{
ClassB* pb = dynamic_cast<ClassB*>(pa);
if( pb ) ...
(Обратите внимание, что это работает только в иерархиях полиморфных классов. То есть должны быть виртуальные задействованные функции.)
Однако вам следует избегать этого. Зачем вам это, что нельзя решить с помощью виртуальных функций?
Другие указали, что переключение типов обычно является плохой идеей, поэтому я не буду этого делать. Если вам действительно нужно это сделать, вы можете использовать оператор typeid
для включения динамического типа объекта:
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
похож, но проверяет конвертируемость, а не равенство:
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 */
}
}
Они работают, только если ClassA
полиморфен (то есть имеет хотя бы одну виртуальную функцию).
Используйте dynamic_cast
следующим образом:
ClassA* SomeClass::doSomething(ClassA* a)
{
if (dynamic_cast<DerivedClass*>(a)) {
...
} else if (dynamic_cast<BaseClass*>(a)) {
...
}
}
dynamic_cast
вернет 0
в случае, если ptr
не является указателем типа T
, и в противном случае вернет указатель типа T
.
dynamic_cast
обычно можно избежать, и это индикатор плохого дизайна / кода. Если вы можете этого избежать, попробуйте сделать это, поскольку для этого требуется RTTI в вашем последнем исполняемом файле.