2016-09-03 3 views
1

У меня проблема с некоторыми рефакторингами, которые я пытаюсь сделать. У нас много дублирования кода, и я пытаюсь разобраться в этом. У меня есть следующая структура классовРефакторинг с использованием абстрактных базовых классов и шаблонов в C++

IMessageSink.h:

class IMessageSink 
{ 
public: 
    virtual ~IMessageSink() { }; 
    virtual void process(const taurus::Msg& msg) = 0; 
}; 

У меня есть следующий базовый класс ModelBase.h, которые все модели должны наследовать, на данный момент, пожалуйста, не используйте из friend class EM:

class ModelBase : public virtual IMessageSink 
{ 
public: 
    ModelBase(Tag a); 

    void process(const taurus::Msg& msg); 
    void reset(); 

private: 
    friend class EM; // I will ask about this below. 

    virtual void calculate(double lambda) = 0; 
}; 

реализация friend EM не является правильным, и я спрашиваю об этом ниже. Я тогда есть класс, который реализует/наследует от ModelBase, ModelM0.h:

class ModelM0 : public virtual ModelBase 
{ 
public: 
    ModelM0(Tag a); 

    static ModelM0* ModelM0::make(Tag a) 
    { 
     ModelM0* m = new ModelM0(a); 
     m->reset(); 
     return m; 
    } 

private: 
    void calculate(double lambda); 
}; 

с ModelM0.cpp реализован как:

ModelM0::ModelM0(Tag a) : ModelBase(a) { } 

void ModelM0::calculate(double lambda) 
{ 
    // Do stuff. 
} 

Проблема с классом EM другу и как реализовать это в общем виде. Раньше этот класс работал только с типами ModelM0, которые не наследовали от ModelBase. Теперь другие модели также наследуют от ModelBase и EM также должны работать с ними - вот в чем проблема. У меня есть следующее определение в EM.h (который я изменил в шаблон таким образом, мы можем определить тип ModelBase мы используем TModel):

с EM.h как:

template <class TModel> 
class EM : public virtual IMessageSink 
{ 
public: 
    static EM* make(Tag a) 
    { 
     return new EM(a); 
    } 

    EM(Tag a); 
    ~EM(); 

    void process(const taurus::Msg& msg); 
    void run(); 
private: 
    struct Bucket 
    { 
     TModel* _model; 
     std::vector<TinyMatrix<1, 1> > _obs 
    }; 

    EM::Bucket& getModel(int ag); 
} 

реализация проблема заключается в EM::Bucket& getModel(int ag);, в EM.cpp мы имеем

template<class TModel> 
EM<TModel>::EM(Tag a) { } 

template<class TModel> 
EM<TModel>::~EM() 
{ 
    run(); 
} 

template<class TModel> 
void EM<TModel>::process(const taurus::Msg& msg) 
{ 
    int ag = getMessageCount(msg.type()); // External call. 
    if (ag <= 3) 
    { 
     Bucket& b = getModel(ag); 
     TModel* m = b._model; 
     m->process(msg); 
    } 
} 

выше, кажется, будет хорошо, моя проблема реализация getModel

template<class TModel> 
EM<TModel>::Bucket& EM<TModel>::getModel(int ag) 
{ 
    // This is not right. 
    TModel* m; 
    m = TModel::make(getTag(ag)); // This is not right - I need a factory. 

    // ... Do stuff. 

    Bucket& b = // Get a bucket. 
    b._model = m; 

    return b; 
} 

Мои вопросы:

  1. Как я могу изменить код выше, так что в EM<TModel>::getModel(int ag) я могу создать правильный TModel используя make в выше - мне нужен завод и как это будет реализовано?

  2. В ModelBase.h класс EM указан как класс друга. Как это может быть сделано мной для работы с используемым типом TModel (ModelBase)?

Важно отметить, что это рефакторинг вопрос, не является ли или-не код, который я показал в методах является правильным или правильным (это было вырубать, чтобы кратко выделить мои проблемы). Рефакторинг - единственное, с чем мне хотелось бы помочь. Большое спасибо за ваше время.

+1

Да, потому что код не компилируется. Обзор кода предназначен только для рабочих примеров ... – MoonKnight

+1

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

+0

Пожалуйста, добавьте ошибку (-ы) компилятора. – grek40

ответ

1

Когда я попытался получить код компиляции, я должен был исправить несколько не хватает запятой и недостающих типов (Tag, taurus::Msg, TinyMatrix), а также зафиксировать объявление и определение getModel(int ag)

Как правило, вам нужно указать компилятору, что Bucket - это фактически имя типа, а не какой-либо другой параметр.

Для декларации у вас есть 2 варианта:

Bucket& getModel(int ag); // (1) 
typename EM<TModel>::Bucket& getModel(int ag); // (2) 

(1) подразумевается использование типа Bucket текущей специализации шаблона. (2) является явным использованием типа вместе с ключевым словом typename для компилятора, как упомянуто выше.

Для определения вам обязательно нужно указать ключевое слово typename, так как вы находитесь вне контекста определения класса.

template<class TModel> 
typename EM<TModel>::Bucket& EM<TModel>::getModel(int ag) 
{ 
    // This is not right. 
    TModel* m; 
    m = TModel::make(getTag(ag)); // This is not right - I need a factory. 

    // ... Do stuff. 

    Bucket& b = // Get a bucket. 
     b._model = m; 

    return b; 
} 

Просто игнорируйте «Это неправильно». комментарии - я скопировал их из вашего образца кода. На самом деле это совершенно правильно.

Для объявления friend вам необходимо добавить версию шаблона, так как вы хотите подружиться со всеми возможными экземплярами шаблонов. Я посмотрел его с this answer (кредитов на Anycorn)

Надежда, которая решает все ваши вопросы. Я использовал template <class>, так как вы его использовали. Лично я предпочитаю template <typename>.

+0

Я просто перечитываю вопрос. Посмотрим на аспект «друга», который я еще не рассматривал. Однако большую часть времени, требуя «друга», является индикатором основных проблем дизайна. – grek40

+0

Большое спасибо за вашу помощь и время здесь. Я воспользуюсь предлагаемым изменением и вернусь с ошибками компилятора ... – MoonKnight

+0

@ Killercam см. Мое редактирование внизу. – grek40