2009-06-11 115 views
0

我们有一个类层次结构,看起来是这样的:相同的功能,不同的返回类型的类层次

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

二OO解决方案是创建一个类返回类型。然后,您可以将此返回类型转换为专门的返回类型。

在任何情况下,使用浮点数学的金钱会让你陷入困境。

+0

我同意usinig浮点数学重复乘法/除法是不是一个好主意。这只是一个说明性的例子。事后看来,我可以选择另一种手术。 – Andy 2009-06-11 15:07:05

5

虽然我不能说我有一个函数返回不同类型的多个派生类的想法,有一种方法可以做到这一点。

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中用于地图等的方法类似。

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>{ 
}; 
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_pricem_quantity公众,以便基类可以访问它们。您可能不想这样做,所以您需要添加公共访问器(或者使用那些已存在的访问器,如果有的话),或者使它们成为基类的受保护成员(由typedefs指定的类型)在派生类中),或者让派生类将基类声明为朋友。

如果你想公开getValue成员函数,你可以将它添加到基类并使继承公开。

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; 
};