2016-06-23 9 views
0

В приведенном ниже примере у меня есть довольно типичный пример CRTP, два разных производных класса, у которых есть метод bar. Базовый класс имеет метод foo который только вперед к некоторым производный bar методИтерации по различным CRTP Методам производных классов

#include <iostream> 

template<typename Derived> 
class Base { 
public: 
    void foo() { 
     static_cast<Derived*>(this)->bar(); 
    } 
}; 

class DerivedA : public Base<DerivedA> { 
public: 
    void bar() { 
     ::std::cout << "A\n"; 
    } 
}; 

class DerivedB : public Base<DerivedB> { 
public: 
    void bar() { 
     ::std::cout << "B\n"; 
    } 
}; 

int main() { 
    DerivedA a; 
    DerivedB b; 
    a.foo(); 
    b.foo(); 
} 

Это не кажется, что я могу иметь массив/вектор/и т.д. базового класса, поскольку он должен был бы иметь тип вдоль линий Base<T> где T отличается

есть ли какое-то конвенция без virtual для возможности перебрать различные производные классы при условии, все они имеют один и тот же метод (bar в данном случае)?

ответ

2

Вы можете использовать Boost.Variant. Например:

typedef boost::variant<DerivedA, DerivedB> Derived; 

struct BarCaller : public boost::static_visitor<void> { 
    template <class T> 
    void operator()(T& obj) { 
     obj.bar(); 
    } 
}; 

int main() { 
    std::vector<Derived> vec{DerivedA(), DerivedB(), DerivedA()}; 

    BarCaller bar; 
    for (Derived& obj : vec) { 
     obj.apply_visitor(bar); 
    } 
} 

Это позволяет хранить разнородные типы в векторе или другой STL контейнера (с помощью «предвзято союз»), и позволяет вызвать определенную функцию на всех из них независимо от того, что они не имеющие общего предка или любых виртуальных методов.

+0

Вы опубликовали бы полный пример? Я не использовал 'boost :: variant' до – asimes

+0

Я предполагаю, что больше не будет' Base', а остались только 'DerivedA' и' DerivedB'? – asimes

+0

@asimes: ОК, я немного изменил свой ответ как полную, управляемую программу, если вы объедините ее с определениями классов. Неважно, есть ли у вас 'Base' или нет - мой код работает в любом случае. –

3

Это не кажется, что я могу иметь массив/вектор/и т.д. базового класса, поскольку он должен был бы иметь тип вдоль линий Base<T> где T отличается.

Вы можете иметь базовый класс для всех Base<T>T, то вы можете иметь список/вектор/массив указателей на базовый класс, если это работает для вас.

struct BaseOne 
{ 
    virtual void foo() = 0; 
    virtual ~BaseOne() {} 
}; 

template<typename Derived> 
class Base : struct BaseOne { 
public: 
    void foo() { 
     static_cast<Derived*>(this)->bar(); 
    } 
}; 

, а затем,

int main() { 
    std::vector<BaseOne*> v {new DerivedA, new DerivedB }; 
    for (auto item : v) 
     item->bar(); 

    for (auto item : v) 
     delete item; 
} 

Есть ли какие-то конвенции без virtual за возможность перебирать различные производные классы предполагая, все они имеют один и тот же метод (bar в данном случае)?

Нет, не существует.