Проверьте на производный тип (C++)

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

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

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

    }
}

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

7
задан ThomasMcLeod 7 July 2015 в 19:40
поделиться

6 ответов

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

    }
}
23
ответ дан 6 December 2019 в 04:49
поделиться

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

4
ответ дан 6 December 2019 в 04:49
поделиться

Немного отличается от того, что вы просили

ClassB* b;
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) {
    // not a classB*
} else {
    // a classB* in b
}
2
ответ дан 6 December 2019 в 04:49
поделиться

Синтаксис следующий:

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

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

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

3
ответ дан 6 December 2019 в 04:49
поделиться

Другие указали, что переключение типов обычно является плохой идеей, поэтому я не буду этого делать. Если вам действительно нужно это сделать, вы можете использовать оператор 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
ответ дан 6 December 2019 в 04:49
поделиться

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

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

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

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

17
ответ дан 6 December 2019 в 04:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: