派生类模板

Derived class template

本文关键字:派生      更新时间:2023-10-16

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

// 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);

我有模板设置参数功能:

// 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]);

非常感谢。

我的评论似乎将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纯虚拟

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,然后返回到没有CRTParameter的状态。

但根据我对此类结构的经验,CTemplateParameter中的事情很快就会变得一团糟,最好由额外的层来处理。

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

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

3/不可以。您不能将CtemplateParameter<float>强制转换为CtemplateParameter<void*>

1) 如何单独设置所有参数?

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

std::map<CParameter*, std::function<void()>> mySets;
// ...
mySets.emplace(&parameter, [ObjectThatGiveMeNext, &parameter]() {
    parameter.setParameter(ObjectThatGiveMeNext.get());
});

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

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

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

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

这是不可能的——这是一个你不知道类型的上下文,所以你必须知道类型(开关情况)或依赖多态行为。我认为这里最好的方法是依赖多态行为。

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

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

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

3) 我可以得到这样的派生类类型吗?或者如何转换?

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