2015-08-25 5 views
1

У меня есть некоторые общие типы данных и некоторые производный тип (ы):абстрактные классы и шаблоны

class abstract_data { virtual void foo() {}; }; 
class derived_data : public abstract_data { void foo() {} }; 

Я хочу написать несколько классов, которые работают над этими данными. Что бы я как сделать это:

class abstract_worker { 
public: 
    virtual void apply(abstract_data&) = 0; 
}; 

class derived_worker : public abstract_worker { 
public: 
    void apply(derived_data&) {} ; 
}; 

Это не работает, потому что компилятор просит меня реализовать void apply(abstract_data&). Я вижу две альтернативы.

1.alternative:

class abstract_worker { 
public: 
    virtual void apply(abstract_data&) = 0; 
}; 

class derived_worker : public abstract_worker { 
public: 
    void apply(abstract_data& data) { 
     derived_data& internal_data = dynamic_cast<derived_data&>(data); 
    } 
}; 

2. альтернатива:

template<class DATA_TYPE> 
class abstract_worker { 
public: 
    virtual void apply(DATA_TYPE&) = 0; 
}; 

class derived_worker : public abstract_worker<derived_data> { 
public: 
    void apply(derived_data&) { } 
}; 

Я не люблю их обоих. В 1-й альтернативе параметр объявляется как abstract_data&, хотя он действительно должен быть derived_data&.

Во второй альтернативе теряется, что параметр имеет тип abstract_data&. Это еще более проблематично, если apply(abstract_data&) не является чисто виртуальным, но использует некоторую функциональность abstract_data. Вы запускаете в situtation, где abstract_data& неявно требуется как DATA_TYPE, но явно не объявлено как таковое.

Однако я хочу сохранить отношения типа.

Есть ли другой способ? Если бы не тот, который вы бы предпочли?

+3

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

+4

Ваш предпочтительный 'производный_работник' не соответствует Принципу замещения Лискова, что указывает на плохой дизайн. Почему «производный_оператор» является «абстрактным_работником», если все «абстрактные_работники» могут работать со всеми «абстрактными_датами», а «производный_работник» не может? – Angew

+3

Это не место для использования виртуальных функций. Они предназначены для тех случаев, когда вы не знаете динамический тип объекта. Ваш производный работник знает, что он хочет получить производного. –

ответ

0

Вы можете использовать статические проверки, чтобы предотвратить DATA_TYPE не унаследовав от abstract_data: #include

class abstract_data { virtual void foo() {}; }; 
class derived_data : public abstract_data { void foo() {} }; 
class faulty_data { void foo() {} }; 

template<class DATA_TYPE> 
class abstract_worker { 
    static_assert(std::is_base_of<abstract_data, DATA_TYPE>::value, "DATA_TYPE does not inherit from abstract_data"); 

public: 
    virtual void apply(DATA_TYPE&) = 0; 
}; 

class derived_worker : public abstract_worker<derived_data> { 
public: 
    void apply(derived_data&) {} 
}; 

class faulty_worker : public abstract_worker<faulty_data> { 
public: 
    void apply(faulty_data&) {} 
}; 

Выхода во время компиляции:

1>------ Build started: Project: Test_Call, Configuration: Debug Win32 ------ 
1> Source.cpp 
1><PROJ_PATH>\source.cpp(9): error C2338: DATA_TYPE does not inherit from abstract_data 
1> <PROJ_PATH>\source.cpp(20): note: see reference to class template instantiation 'abstract_worker<faulty_data>' being compiled 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 
Смежные вопросы