Reputation: 2830
We have a class hierarchy which looks something like this:
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();
};
Now we need to write a function which computes the value by multiplying the price and quantity. The aim is to make it as simple as possible to add new classes in the future. As you may be aware, this is not straightforward because the data types of these fields are different for different classes. In effect, we have these functions to do the same thing conceptually, but in programming terms they are different operations.
To minimise the amount of cut and paste required, the solution I can think of so far is to use template functions:
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);
}
};
It does its job all right, but this will mean that I have to define every single member function in each class. For example, I will need another lot of these template functions if I want to have a function called getValue, say.
The data types of the class members are known when the class is defined, so having to put them in the function definitions again seem to be a duplication. Is there a possible way to avoid all this template business in the function definitions?
Thank you.
Andy
PS I have seen the following question, but the issue in that question is slightly different: Returning different data type depending on the data (C++)
Upvotes: 0
Views: 3517
Reputation: 1605
You could do:
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; };
Upvotes: 0
Reputation: 279255
Use the Curiously Recurring Template Pattern (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;
};
Note that I've had to make m_price
and m_quantity
public in order that the base class can access them. You probably don't want to do that, so instead you will need either to add public accessors (or use the ones which are there already, if any), or else make them protected members of the base class (of types specified by typedefs in the derived class), or else have the derived class declare the base class a friend.
If you want a public getValue
member function, you can add it to the base class and make the inheritance public.
Upvotes: 1
Reputation: 57202
Would something like this do?
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>{
};
Upvotes: 0
Reputation: 16583
While I can't say I like the idea of having multiple derived classes with a function that returns different types, there is a way to do this.
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;
};
This lets you vary the value_type in the derived class, but declare all your common functions in the base (like you ought to do). This is similar to the approach used in the STL for maps and such.
Upvotes: 6
Reputation: 152817
The OO solution would be to create a class of the return type. You can then subclass this return type for specialized return types.
In any case, using floating point math for money will get you in trouble.
Upvotes: 0