我们有一个类层次结构,如下所示:
class base
{
};
class derived1 : protected base
{
private:
float m_price;
int m_quantity;
float m_value;
public:
// float calculateValue();
};
class derived2 : protected base
{
private:
double m_price;
long m_quantity;
double m_value;
public:
// double calculateValue();
};
现在我们需要编写一个函数,通过乘以价格和数量来计算价值。目的是尽可能简单地在将来添加新类。您可能知道,这并不简单,因为这些字段的数据类型对于不同的类是不同的。实际上,我们有这些函数在概念上做同样的事情,但在编程术语中它们是不同的操作。
为了尽量减少所需的剪切和粘贴量,我能想到的解决方案是使用模板函数:
template <class A, B, C>
A calculate_value(B price, C quantity)
{
A result;
// Some code to do the multiplication, not sure if template specialisation is needed
return result;
};
class derived1 : protected base
{
private:
float m_price;
int m_quantity;
float m_value;
public:
float calculateValue()
{
calculate_value < float, float, int > (m_price, m_quantity);
}
};
它可以完成任务,但这意味着我必须在每个类中定义每个成员函数。例如,如果我想要一个名为getValue的函数,我将需要另外很多这些模板函数。比如说。
在定义类时,类成员的数据类型是已知的,因此必须将它们再次放入函数定义中似乎是重复的。有没有办法在函数定义中避免所有这些模板业务?
谢谢。
安迪
PS我看到了以下问题,但该问题的问题略有不同: Returning different data type depending on the data (C++)
答案 0 :(得分:6)
虽然我不能说我喜欢让多个派生类与一个返回不同类型的函数的想法,但有一种方法可以做到这一点。
template
class base<typename value_type>
{
public:
value_type calculateValue();
};
class derived1 : protected base<float>
{
private:
float m_price;
int m_quantity;
float m_value;
};
class derived2 : protected base<double>
{
private:
double m_price;
long m_quantity;
double m_value;
};
这使您可以改变派生类中的value_type,但是在基础中声明所有常用函数(就像您应该这样做)。这类似于STL中用于地图等的方法。
答案 1 :(得分:1)
使用奇怪的重复模板模式(CRTP):
template <typename DERIVED>
class base {
protected:
typename DERIVED::value_type calculateValue() {
DERIVED *self = static_cast<DERIVED *>(this);
return self->m_price * self->m_quantity;
}
};
class derived1 : protected base<derived1> {
public:
typedef float value_type;
float m_price;
int m_quantity;
};
class derived2 : protected base<derived2> {
public:
typedef double value_type;
double m_price;
long m_quantity;
};
请注意,我必须公开m_price
和m_quantity
,以便基类可以访问它们。您可能不希望这样做,因此您需要添加公共访问器(或使用已存在的访问器,如果有的话),或者使它们成为基类的受保护成员(由typedef指定的类型)在派生类中,或者让派生类将基类声明为朋友。
如果您需要公共getValue
成员函数,可以将其添加到基类并将继承公开。
答案 2 :(得分:0)
OO解决方案是创建一个返回类型的类。然后,您可以将此返回类型子类化为专门的返回类型。
在任何情况下,使用浮动数学计算都会让你遇到麻烦。
答案 3 :(得分:0)
会这样吗?
template <typename A,typename B,typename C>
class base{
protected:
A m_price;
B m_quantity;
C m_value;
public:
C calculateValue(){
m_value = m_quantity * m_price;
return m_value;
}
};
class derived1 : public base<int,float,int>{
};
class derived2 : public base<long,double,long>{
};
答案 4 :(得分:0)
你可以这样做:
template class base { public: void calculateValue(value_type& x); }; class derived1 : protected base { private: float m_price; int m_quantity; float m_value; }; class derived2 : protected base { private: double m_price; long m_quantity; double m_value; };