派生类模板
Derived class template
我对派生类模板有一些问题。我有这样的基础和派生类模板:
// 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(¶meter, [ObjectThatGiveMeNext, ¶meter]() {
parameter.setParameter(ObjectThatGiveMeNext.get());
});
即使包含参数,它也不是参数的主要容器。这只是为了跟踪哪个参数与哪个函数相关联。
理想情况是在创建参数时创建此函数,因为您知道参数的类型。
另一个解决方案是创建一个虚拟函数updateValue
,该函数将用this
调用setParameter
。
2) 如果没有枚举,我可以获取参数的类型并在运行时创建一个类型吗?
这是不可能的——这是一个你不知道类型的上下文,所以你必须知道类型(开关情况)或依赖多态行为。我认为这里最好的方法是依赖多态行为。
我会为此添加一个虚拟功能克隆。也许不是著名的直clone
函数,而是一个克隆函数,它返回参数和函数来设置其值。有点像:
std::tuple<std::unique_ptr<CParameter>, std::function<void()>> clone();
在这种情况下,考虑使用typedef或,因为类型是loooooong。
3) 我可以得到这样的派生类类型吗?或者如何转换?
不,你不能。您需要将类的实例转换为另一个不相关的类型。我不会那样做。相反,将处理特定派生类的代码保留在明确知道类型的位置,并将泛型代码保留为泛型代码(例如:不试图知道类型)。这是我现在能告诉你的最好的建议。
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么此派生对象无法访问基类的后递减方法?
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践