在 C++ 中使用抽象基础 类 和模板进行重构
Refactoring using Abstract Base Classes and Templates in C++
我尝试进行一些重构时遇到问题。我们有很多代码重复,我正在努力解决这个问题。我有以下 class 结构
IMessageSink.h:
class IMessageSink
{
public:
virtual ~IMessageSink() { };
virtual void process(const taurus::Msg& msg) = 0;
};
我有以下基础 class 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
的实现不正确,我在下面询问。然后我有一个 class 那 implements/inherits 从 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
朋友 class 以及如何以通用方式实现它。以前,此 class 仅适用于未从 ModelBase
继承的类型 ModelM0
。现在其他模型也继承自 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;
}
我的问题:
如何更改上面的代码,以便在 EM<TModel>::getModel(int ag)
中我可以使用上面的 make
创建正确的 TModel
- 我需要一个工厂吗这将如何实施?
在ModelBase.h
中EM
class被指定为朋友class。这个我如何使通用的与正在使用的 TModel
(ModelBase
) 类型一起工作?
这里需要注意的是,这是一个重构问题,而不是我在方法中显示的代码是否正确或正确(为了简洁地突出我的问题)。重构是我唯一想要帮助的事情。非常感谢您的宝贵时间。
当我试图让你的代码编译时,我不得不修复一些缺失的分号和缺失的类型(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
关键字,因为您不在 class 定义上下文中。
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;
}
忽略 "This is not right." 注释 - 我从您的示例代码中复制了它们。其实完全正确。
对于 friend
声明,您需要添加一个模板版本,因为您希望友好所有可能的模板实例化。我从 this answer(Anycorn 的致谢)
中查找
template <class> friend class EM;
希望能解决您所有的问题。请注意,我使用 template <class>
因为您使用了它。我个人更喜欢 template <typename>
.
我尝试进行一些重构时遇到问题。我们有很多代码重复,我正在努力解决这个问题。我有以下 class 结构
IMessageSink.h:
class IMessageSink
{
public:
virtual ~IMessageSink() { };
virtual void process(const taurus::Msg& msg) = 0;
};
我有以下基础 class 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
的实现不正确,我在下面询问。然后我有一个 class 那 implements/inherits 从 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
朋友 class 以及如何以通用方式实现它。以前,此 class 仅适用于未从 ModelBase
继承的类型 ModelM0
。现在其他模型也继承自 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;
}
我的问题:
如何更改上面的代码,以便在
EM<TModel>::getModel(int ag)
中我可以使用上面的make
创建正确的TModel
- 我需要一个工厂吗这将如何实施?在
ModelBase.h
中EM
class被指定为朋友class。这个我如何使通用的与正在使用的TModel
(ModelBase
) 类型一起工作?
这里需要注意的是,这是一个重构问题,而不是我在方法中显示的代码是否正确或正确(为了简洁地突出我的问题)。重构是我唯一想要帮助的事情。非常感谢您的宝贵时间。
当我试图让你的代码编译时,我不得不修复一些缺失的分号和缺失的类型(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
关键字,因为您不在 class 定义上下文中。
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;
}
忽略 "This is not right." 注释 - 我从您的示例代码中复制了它们。其实完全正确。
对于 friend
声明,您需要添加一个模板版本,因为您希望友好所有可能的模板实例化。我从 this answer(Anycorn 的致谢)
template <class> friend class EM;
希望能解决您所有的问题。请注意,我使用 template <class>
因为您使用了它。我个人更喜欢 template <typename>
.