2015-05-03 4 views
0

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

 class Foo{ 
      virtual void work() = 0; 
... 
     }; 

     class FooLeaf : public Foo{ 
      virtual void work() override{} 
... 
     }; 

     class FooComposite : public Foo{ 
      std::vector<Foo *> foos; 
      virtual void work() override{ 
       for (auto foo : foos){ 
        foo->work(); 
       } 
      } 
... 
     }; 

Не проблема переопределить один метод. Но когда число методов растет, код получает огромное WET. Я имею в виду, что я не чувствую себя хорошо, скопировав цикл foreach, скажем, 10 методов.

+2

Зачем вам копировать этот цикл N раз? если он делает то же самое в каждом классе, просто реализует его в базовом классе ... –

+0

@EdS. Ты не сделал и не понял, что я имел в виду. Я спрашиваю, что мне делать, когда у меня есть несколько разных методов в Foo и вы хотите реализовать их по-другому в FooComposite. Как правило, они очень похожи друг на друга внутри FooComposite, когда они перегружены - для цикла и внутри метода из foos, хранящихся в векторе. – bartop

+0

Бог благословит их - макросы * потрясающие * за этот материал ... ;-). –

ответ

0

Если все, что вам нужно сделать, это избавиться от петли, но не против повторения имени метода, вы можете инкапсулировать итерацию (и, возможно, любую обработку ошибок) в шаблон Composite, а затем вы можете использовать лямбда для переадресации вызова каждому элементу композита.

template <typename ElementType> 
class Composite : public ElementType { 
private: 
    std::vector<ElementType*> container; 

protected: 
    template < typename Fn> 
    auto apply (Fn && fn) { 
     for (auto& e : container) { 
      fn(*e); 
     } 
    } 
}; 

class Foo{ 
public: 
    virtual void work() = 0; 
}; 

class FooLeaf : public Foo{ 
    virtual void work() override { } 
}; 

class FooComposite : public Composite<Foo> { 
    virtual void work() override { 
     return apply([](Foo& f){f.work();}); 
    } 
}; 

Даже лучше, вы можете инкапсулировать добавление элементов в композит с помощью шаблона Composite класса, который, возможно, где она принадлежит. Реализация apply опирается на некоторые функции вывода типа C++ 14, чтобы сделать его немного легче писать и смотреть.

+0

Это в основном то, что я хотел, но проблема все еще возникает, когда я хочу переопределить около 10 методов в составном, или еще хуже - когда я пытаюсь создать общий состав и не знаю, сколько методов базового класса. Я имею в виду - все еще есть очень похожие части кода, которые скопированы с копией. – bartop

+0

Я думаю, что вам нужно прибегать к макросам или другому инструменту, генерирующему код, например, вашей IDE. Проблема в том, что язык не может разумно угадать, какие виртуальные методы из его баз должны быть реализованы. Это знание является областью программирования, а не языком. –

+0

Я также должен сказать, что это использование 'apply' может быть еще более упрощено за счет использования общих лямбда, которые должны быть доступны в предстоящем стандарте, и во многих компиляторах раньше этого. –

1

Если все методы имеют одинаковую сигнатуру, вы можете использовать метод указатели:

class Foo{ 
    public: 
    virtual void work() = 0; 
    virtual void rest() = 0; 
}; 

class FooComposite : public Foo { 
    std::vector<Foo *> foos; 

    void do_all(void (Foo::*method)()) { 
    for (auto foo : foos) { 
     (foo->*method)(); 
    } 
    } 

    void work() override { 
    do_all(&Foo::work); 
    } 
    void rest() override { 
    do_all(&Foo::rest); 
    } 
}; 
+0

Ницца, но - ничтожное , извините - было бы лучше указать 'override' вместо' virtual' в 'FooComposite'. Не то, чтобы это было необходимо или полезно для этого точного Q, но это можно обобщить на шаблон посетителя. –

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