在C ++中使用抽象基类和模板进行重构

时间:2016-09-03 11:44:50

标签: c++ templates inheritance refactoring class-design

我正在尝试进行一些重构。我们有很多代码重复,我试图解决这个问题。我有以下类结构

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。现在其他模型也继承自ModelBaseEM也需要使用这些 - 这就是问题所在。我在 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类被指定为朋友类。我如何使用TModelModelBase)类型来使用泛型?

  3. 重要的是要注意这是一个重构问题,而不是我在方法中显示的代码是否正确或正确(为了简明扼要地强调我的问题,这已被删除) )。重构是我唯一想要帮助的事情。非常感谢你的时间。

1 个答案:

答案 0 :(得分:1)

当我尝试编译代码时,我必须修复一些缺少的分号和缺少的类型(Tagtaurus::MsgTinyMatrix)并修复声明和定义getModel(int ag)

通常,您需要向编译器指出Bucket实际上是类型名称而不是其他类型的参数。

对于声明,您有两个选择:

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;
}

忽略&#34;这不对。&#34;评论 - 我从示例代码中复制了它们。它实际上是完全正确的。

对于friend声明,您需要添加模板版本,因为您希望与所有可能的模板实例建立友好关系。我从this answer(Credits to Anycorn)

查找了它
template <class> friend class EM;

希望能解决您的所有问题。注意我使用template <class>后使用它。我个人更喜欢template <typename>