c++中使用抽象基类和模板进行重构
Refactoring using Abstract Base Classes and Templates in 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
的类, modelm .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);
};
与 modelm .cpp实现为:
ModelM0::ModelM0(Tag a) : ModelBase(a) { }
void ModelM0::calculate(double lambda)
{
// Do stuff.
}
问题在于EM
朋友类以及如何以通用的方式实现它。以前,这个类只处理没有从ModelBase
继承的ModelM0
类型。现在其他模型也继承了ModelBase
和EM
需要与这些工作-这就是问题所在。我在EM.h中有以下定义(我已经将其更改为模板,以便我们可以指定我们使用TModel
的ModelBase
的类型):
with 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
类被指定为友类。如何使我的通用工作与TModel
(ModelBase
)类型正在使用?
这里需要注意的是,这是一个重构问题,而不是我在方法中展示的代码是否适当或正确(为了简洁地突出我的问题,这里已经被删减了)。重构是我唯一想帮忙的事情。非常感谢您的宝贵时间。
当我试图让你的代码编译时,我不得不修复一些缺失的分号和缺失的类型(Tag
, taurus::Msg
, TinyMatrix
),还修复了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;
}
忽略"This is not right."注释-我从您的示例代码中复制了它们。这是完全正确的。
对于friend
声明,您需要添加一个模板版本,因为您想要使所有可能的模板实例化成为朋友。我从这个答案中查找它(credit to Anycorn)
template <class> friend class EM;
希望这能解决你所有的问题。注意,因为您使用template <class>
,所以我使用了它。我个人比较喜欢template <typename>
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 如何使用基类指针引用派生类成员
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 为什么此派生对象无法访问基类的后递减方法?
- 公开最直接的基类模板名称
- 当基类是依赖类型时,这是一个缺陷吗
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 模板基类中的静态变量
- 重构类:无法将派生类中成员函数的公共代码移回基类
- c++中使用抽象基类和模板进行重构