2016-10-17 2 views
2

Я задал этот вопрос:Идиома для конкретного рефакторинга в C++

Best Way to Refactor Class Hierarchy

в таком плохом состоянии, что я был логически вынужден принять совершенно правильный ответ. Моя проблема заключается в следующем:

У меня есть класс CGrandMother, имеющий открытый метод virtual bool Compute(), что делает

virtual bool Compute() 
{ 
    return false; 
} 

От CGrandMother происходит публично CMother, который не реализует Compute. Теперь от CMother выходят публично C1 и C2, которые действительно реализуют virtual bool Compute(). Теперь virtual bool C1::Compute() и virtual bool C2::Compute() соответственно делают много материала, соответствующего соответственно C1, и до C2, но также много одинакового материала, соответствующего CMother. Теперь есть класс CFamily, имеющие в качестве члена указателя на CMother и почти везде в коде Compute вызывается через строки вида

ptrCMother->Compute(); 

Я хочу вынесут общие вещи, связанные с CMother сделано в C1 и C2 так что мне не придется менять все эти ptrCMother->Compute();. Конечно, я могу создать функцию-член в CMother, сделав это, и позвоните последнему в bool C1::Compute() и bool C2::Compute(). Но ...

В c++, если у вас есть B, вытекающие из A, A::dostuff() и B::dostuff() и если p указывает на тип B то p->dostuff() выполнит B::dostuff() полиморфизмом. Я хотел бы знать, есть ли идиома/шаблон, позволяющий мне это сделать: «p->dostuff()» будет исполнять «A::dostuff()» или нет (согласно bool, скажем), а затем «B::dostuff()», что, конечно же, не происходит в c++ для функции-члены класса, которые не являются конструкторами и т. д.

Чтобы быть ясным: базовый метод не вызывается до того, как его соответствующий производный метод вызывается косвенным образом. Есть ли идиома/шаблон, позволяющий вызывать метод base base (или нет, согласно bool) до его соответствующего производного метода?

+0

Вы можете сделать 'p-> A :: dostuff()' для запуска функции 'A' функции. – Galik

+0

Я знаю, но мне бы хотелось, чтобы он запускался по умолчанию (в этой идиоме), когда 'p-> B :: dostuff()' побежал –

+0

Проголосовало за закрытие как неясное. Я считаю себя достаточно свободно владеющим C++. Бесчисленное количество раз я решал другие проблемы C++. Но этот вопрос включает только базовые вещи, и все же я не понимаю, что это значит. –

ответ

0

Что не так с решением, которое вы упомянули, состоящим в создании метода в классе CMother, который вызывается его дочерними элементами?

#include <iostream> 
#include <memory> 
using namespace std; 

class CGrandMother 
{ 
private: 
    virtual bool _Compute() 
    { 
     return false; 
    } 
public: 

    bool Compute() 
    { 
     return _Compute(); 
    } 
}; 

class CMother : public CGrandMother 
{ 
protected: 
    void _CommonStuff() 
    { 
     cout << "work common to children" << endl; 
    } 
}; 

class C1 : public CMother 
{ 
private: 
    virtual bool _Compute() override 
    { 
     _CommonStuff(); 
     cout << "work specific to C1" << endl; 

     return true; 
    } 
}; 

class C2 : public CMother 
{ 
private: 
    virtual bool _Compute() override 
    { 
     _CommonStuff(); 
     cout << "work specific to C2" << endl; 

     return true; 
    } 
}; 

int main() { 

    unique_ptr<CMother> c1(new C1); 
    unique_ptr<CMother> c2(new C2); 

    c1->Compute(); 
    c2->Compute(); 

    return 0; 
} 

Обратите внимание, что я сдерживал модификаторы доступа из моих классов:

  • Там нет общественной виртуальной функции, следуя шаблон Non-Virtual Interface. Функция, которая является как общедоступной, так и виртуальной, имеет два задания: она определяет интерфейс и реализацию и часто оказывается плохим для обоих.
  • Метод _CommonStuff() защищен, так что не видно остального мира, но до сих пор отозваны подклассами

Кроме того, вы делаете CMother наследуют публично от CGrandMother, что означает, что CMother a CGrandMother. Это действительно так?

Обратите внимание, что если бы CMother был главой иерархии, вы могли бы вызвать _CommonStuff() через свой общедоступный (но не виртуальный!) Метод Compute, и все подклассы автоматически вызывают _CommonStuff(). Это одна из самых больших вещей об этой схеме: Вы можете легко сделать свой Compute() метод выполнения работы, которая является общей для всех подклассов, проверить инварианты и т.д.

Это будет выглядеть так: https://ideone.com/vXd4fL

Я удалил CGrandMother и CMother теперь являются главой моей иерархии. В своем общедоступном методе Compute() я вызываю _CommonStuff(). Детям нужно реализовать _Compute(). _CommonStuff() будет вызываться автоматически всеми детьми при вызове Compute().

+0

Ничего особенного в этом решении не было, за исключением того, что после рефакторинга у вас все еще есть дубликат кода, поскольку вам все равно придется вызывать выполнение факторизованного кода, в каждом «производном» 'Compute()' s он должен быть выполнен , что немного беспокоило меня. :-) Thx для вашего ответа, я анализирую его прямо сейчас. Из любопытства: как называется этот шаблон? –

+0

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

+0

Я имею в виду шаблон, который называется не виртуальным интерфейсом. В основном он утверждает, что метод не должен быть открытым и виртуальным. См. Http://www.gotw.ca/publications/mill18.htm за отличное объяснение. Я отредактировал мое сообщение, чтобы добавить еще одно решение, которое отлично работает, если CMother является главой иерархии классов. – fireboot

Смежные вопросы