2017-02-04 2 views
2

Инструменты анализа статического кода имеют тенденцию часто болтать о «понижении базового класса к производному классу», и я также нашел пару стандартных руководств по кодированию, в которых упоминается, что это не так, поэтому я был интересно, что является лучшим способом.Превосходная практика Downcasting (C++)

Вот мой случай использования:

У меня есть базовый (интерфейс), DerivedA, классы DerivedB, а затем массив, содержащий базы указателей.

Затем я повторяю массив и основываясь на флагове, я определяю, является ли объект DerivedA или DerivedB, отбрасывает его и делает некоторые случайные вещи для объекта извне.

В основном что-то вроде этого:

// arr is of type Base** 
for (int i = 0; i < size; ++i) 
{ 
    // doMagic has an overload for both types 
    if (arr[i]->isDerivedA()) 
    { 
     doMagic(reinterpret_cast<DerivedA*>(arr[i])); 
    }  
    else if (arr[i]->isDerivedB()) 
    { 
     doMagic(reinterpret_cast<DerivedB*>(arr[i])); 
    } 
} 

схватки переинтерпретировать, я не могу использовать dynamic_cast из-за встроенных ограничений платформы (то же самое для C++ 11), но класс Base быть собой интерфейс гарантирует, что объект либо DerivedA, либо DerivedB.

Я мог бы заставить DerivedA и DerivedB реализовывать только чистые виртуальные вызовы, поэтому мне не нужно было бы беспокоиться о том, чтобы что-то удручало, но классы DerivedA и DerivedB очень специализированы, а doMagic делает совершенно разные вещи с экземплярами ...

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

+0

Нужно задаться вопросом, почему '' DerivedA' и DerivedB' получены из 'Base' вообще. В чем цель «базы»? –

+0

Они содержат некоторые распространенные методы, поэтому я не хочу переопределять их, а также некоторые общие элементы данных. Скажем, 50/50 :). Пример может иметь классы: Message, JsonMessage, XmlMessage - и методы parseMessage (JsonMessage *), parseMessage (XmlMessage *) – Maci

+0

Возможно, более чистая архитектура должна заключаться в том, чтобы обернуть общие методы и данные в третий класс и использовать HAS - Отношения с этим третьим классом. Наследование для реализации обычно не является хорошим дизайном ООП. –

ответ

2

Возможно, вам стоит попробовать использовать шаблон посетителя. Вот простой пример:

#include <cstdio> 

class A; 
class B; 
class Visitor { 
public: 
    void visit(A &a) { 
     printf("Visited A\n"); 
    } 

    void visit(B &) { 
     printf("Visited B\n"); 
    } 
}; 


class A { 
public: 
    virtual ~A() { } 

    virtual void applyVisitor(Visitor &v) { 
     v.visit(*this); 
    } 
}; 

class B : public A { 
public: 
    ~B() override { } 

    void applyVisitor(Visitor &v) override { 
     v.visit(*this); 
    } 
}; 


int main() { 
    A a; 
    B b; 

    Visitor v; 

    a.applyVisitor(v); 
    b.applyVisitor(v); 


    return 0; 
} 
+0

Спасибо, это довольно убирает downcast и кажется чище - требуется только немного больше кода. – Maci

1

Если вы знаете, что указатель базового класса указывает на объект производного класса, вы можете использовать static_cast. Компилятор вставляет соответствующий код для корректировки смещений, в отличие от reinterpret_cast или C-Cast.