Проверьте для производного типа (C ++) - PullRequest
7 голосов
/ 01 марта 2010

Как проверить во время выполнения, принадлежит ли объект типу ClassA или производному типу ClassB? В одном случае я должен обрабатывать оба экземпляра отдельно

ClassA* SomeClass::doSomething ( ClassA* )
{
    if( /* parameter is of type base class */) {

    } else if { /* derived class */ ) {

    }
}

Может быть, я мог бы сказать, что у производного класса ClassB есть некоторые специальные возможности. Но как мне это сделать, не меняя существующий класс ClassA?

Ответы [ 6 ]

22 голосов
/ 01 марта 2010

Обычно очень плохая идея включать именно такой тип. Делая это, вы тесно связываете свой метод с производными классами ClassA. Вы должны использовать полиморфизм. Введите метод virtual в классе 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 {

    }
}
15 голосов
/ 01 марта 2010

Используйте dynamic_cast следующим образом:

ClassA* SomeClass::doSomething(ClassA* a)
{
    if (dynamic_cast<DerivedClass*>(a)) {
        ...
    } else if (dynamic_cast<BaseClass*>(a)) {
        ...
    }
 }

dynamic_cast<T *>(ptr) вернет 0 в случае, если ptr не является указателем типа T, и вернет указатель типаT в противном случае.

dynamic_cast обычно можно избежать и является признаком плохого дизайна / кода.Если вы можете избежать этого, попробуйте сделать это, так как для этого требуется RTTI в вашем конечном исполняемом файле.

4 голосов
/ 01 марта 2010

Почему бы не использовать метод doSomething () в ClassB, который обрабатывает дополнительные возможности ClassB? В этом суть полиморфизма.

3 голосов
/ 01 марта 2010

Другие отмечают, что переключение типов обычно плохая идея, поэтому я не буду.Если вам действительно нужно это сделать, вы можете использовать оператор 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 полиморфен (то есть имеет хотя бы одну виртуальную функцию).

3 голосов
/ 01 марта 2010

Синтаксис такой:

ClassA* SomeClass::doSomething ( ClassA* pa )
{
    ClassB* pb = dynamic_cast<ClassB*>(pa);
    if( pb ) ...

(Обратите внимание, что это работает только в полиморфных иерархиях классов. То есть должны быть задействованы виртуальные функции.)

Однако вам следует избегать этого. Что вам нужно для этого, что не может быть решено путем применения виртуальных функций?

2 голосов
/ 01 марта 2010

Слегка отличается от того, что вы просили

ClassB* b;
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) {
    // not a classB*
} else {
    // a classB* in b
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...