派生类模板

时间:2015-11-16 13:52:57

标签: c++ templates derived-class

我对派生类模板有一些疑问。我有这样的基类和派生类模板:

// This is base class
class CParameter {
public:
   CParameter(std::string name) : name(name) {}
// virtual ~CParameter() {} // deleted for good design:)

public:
   std::string name;
};

...

// This is derived class
template <typename T>
class CTemplateParameter : public CParameter {
public:
   CTemplateParameter(std::string name) : CParameter(name) {}
public:
   T parameter;
};

我声明了一些类型参数,将它们推送到基类向量

//Base class parameters
std::vector<CParameter*> parameters; // !
CTemplateParameter<CMatrix4<float>> mat4;
CTemplateParameter<CVector3<float>> vec3;
CTemplateParameter<float> flt;

parameters.push_back(mat4);
parameters.push_back(vec3);
parameters.push_back(flt);

我有模板SetParameter功能:

// This method moved to CParameter base class
template <typename T>
bool SetParameter(const CTemplateParameter<T>& param) {
// switch(typeof(T)) {
// set parameter
if (std::is_same<T, int>::value)
   // gLUniform1i(...)
else if (std::is_same<T, CMatrix4<float>>::value)
   // glUniformMatrix4fv(..)
...

}

所以我的问题:

1)如何设置所有参数个人?

// Notice this function is not template
void SetAll() {
   for each parameter
      SetParameter(parameter[i])
}

2)没有枚举,我可以获取参数类型并在运行时创建一个类型吗?像:

Pseudo code:
    //get type of parameter[i]
    //create a parameter from
    T type = GetTypeofParameter(parameter[i]);
    CTemplateParameter<type> newType;

3)我可以获得这样的派生类类型或如何投射吗?

CTemplateParameter<void*>* p = dynamic_cast<CTemplateParameter<void*>>(parameters[i]);

非常感谢。

3 个答案:

答案 0 :(得分:1)

1 / 您应该在setParameter中将Cparameter定义为抽象方法,并在模板类中实现它。

2 / 我建议使用克隆(或工厂)方法,如我在1 /中建议的那样定义。在此方法中,您可以复制(或创建)对象,然后定义它。

3 / 不可以。您无法将CtemplateParameter<float>投射到CtemplateParameter<void*>

答案 1 :(得分:1)

  

1)如何设置所有参数个人?

除非您知道类型,否则不能迭代并设置所有值的值。并且放置大量的dynamic_cast也不是解决方案,因为它不可扩展。 一种解决方案是保留std::function的地图。这些函数不会接受任何参数并且不返回任何内容。他们将使用正确的值设置参数。推入向量将是这样的:

std::map<CParameter*, std::function<void()>> mySets;

// ...

mySets.emplace(&parameter, [ObjectThatGiveMeNext, &parameter]() {
    parameter.setParameter(ObjectThatGiveMeNext.get());
});

即使您包含参数,它也不是参数的主要容器。它只是跟踪哪个参数与哪个函数相关联。

理想的做法是在创建参数时创建此函数,因为您知道参数的类型。

另一种解决方案是创建一个虚拟函数updateValue,使用setParameter调用this

  

2)没有枚举,我可以获取参数类型并在运行时创建一个类型吗?

这不太可能是你不知道类型的上下文,所以你必须知道类型(切换案例)或依赖多态行为。我认为这里最好的是依靠多态行为。

我会为此添加一个虚拟函数克隆。也许不是着名的直接clone函数,而是一个克隆函数,它返回参数和函数来设置它的值。有点像这样:

std::tuple<std::unique_ptr<CParameter>, std::function<void()>> clone();

考虑一个typedef或在这种情况下使用,因为类型是loooooong。

  

3)我可以获得这样的派生类类型或如何投射吗?

不,你不能。您需要将类的实例转换为另一个类,而不是相关类型。我不会这样做。相反,保持您的代码处理您的特定派生类,您明确知道类型并保持通用代码通用(例如:不试图知道类型)。这是我现在可以告诉你的最佳建议。

答案 2 :(得分:1)

我的评论似乎推动ADesignersEncyclopedia远离模板/虚拟混合,而不是实用的替代方案。最初的问题没有提供足够的信息来决定是否有一个实际的选择。缺乏这样一个实用的替代方案,虚拟/模板混合正确(使用CRTP)而不是完全拒绝它:

在目标类中,您需要两种形式的setParameter,两种形式都不是模板。第一个表单调度到参数类中的setParameter,该类调度回目标类中的第二个表单:

bool SetParameter(const CParameter& param) {
   return param.SetParameter( *this );
}

第二种形式在值类型上重载:

bool SetParameter(int value) {
   // whatever
}
bool SetParameter(CMatrix4<float> const& value) {
   // whatever
}
...

在参数基类中,您需要SetParameter pure virtual

class CParameter
{
    ...
    virtual bool SetParameter( TargetType& ) const = 0;
    ...
};

然后你需要一个CRTP基类,它应该从你的简单基类派生出来:

template<class ActualType>
class CRTPParameter : public CParameter
{
  CRTPParameter(std::string name) : CParameter(name) {}
  ActualType* This() {return static_cast<ActualType*>(this); }
  ActualType const* This() const {return static_cast<ActualType const*>(this); }
  // various things including
  ActualType* clone() const { return new ActualType( *This() ); }
  bool SetParameter( TargetType& target ) const
  { return target.SetParameter( This()->parameter ); }
};

然后您的模板类派生自您的CRTP类

template <typename T>
class CTemplateParameter : public CRTPParameter<CTemplateParameter<T> > {
public:
   typedef CRTPParameter<CTemplateParameter<T> super;
   CTemplateParameter(std::string name) : super(name) {}

如果其他一切都很简单,那么整个CRTP方案可能过度,你可以将clone和SetParameter从CRTPParameter移动到CTemplateParameter并返回到没有CRTPParameter。

但是根据我对这种结构的经验,CTemplateParameter中的事情很快就会被额外层处理得最好。