2009-06-11 7 views
0

Nous avons une hiérarchie de classe qui ressemble à quelque chose comme ceci:Même fonction, différents types de retour pour la hiérarchie des classes

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

Maintenant, nous avons besoin d'écrire une fonction qui calcule la valeur en multipliant le prix et la quantité. Le but est de rendre aussi simple que possible d'ajouter de nouvelles classes dans le futur. Comme vous le savez peut-être, ce n'est pas simple car les types de données de ces champs sont différents pour différentes classes. En effet, nous avons ces fonctions pour faire la même chose sur le plan conceptuel, mais en termes de programmation, ce sont des opérations différentes.

Pour minimiser la quantité de couper et coller nécessaire, la solution que je peux penser à ce jour est d'utiliser les fonctions de modèle:

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

Il fait son travail bien, mais cela signifie que je dois définir chaque fonction membre unique dans chaque classe. Par exemple, j'aurai besoin d'un grand nombre de ces fonctions de template si je veux avoir une fonction appelée getValue, disons.

Les types de données des membres de la classe sont connus lorsque la classe est définie, de sorte que le fait de devoir les replacer dans les définitions de fonction semble être une duplication. Existe-t-il un moyen possible d'éviter toute cette activité de modèle dans les définitions de fonctions?

Merci.

Andy

PS J'ai vu la question suivante, mais la question dans cette question est légèrement différente: Returning different data type depending on the data (C++)

Répondre

0

La solution OO serait de créer une classe de type de retour. Vous pouvez ensuite sous-classer ce type de retour pour les types de retour spécialisés.

Dans tous les cas, l'utilisation du calcul en virgule flottante pour l'argent vous causera des problèmes.

+0

Je suis d'accord que usinig mathématiques à virgule flottante pour la multiplication répétée/division n'est pas une bonne idée. Ceci est juste fait comme un exemple illustratif. Avec le recul, j'aurais pu choisir une autre opération. – Andy

5

Bien que je ne puisse pas dire que j'ai comme l'idée d'avoir plusieurs classes dérivées avec une fonction qui retourne différents types, il y a un moyen de le faire.

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

Cela vous permet de faire varier la value_type dans la classe dérivée, mais déclariez toutes vos fonctions communes dans la base (comme vous devriez le faire). Ceci est similaire à l'approche utilisée dans la liste STL pour les cartes et autres.

0

Est-ce que quelque chose comme ça ferait?

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

Utilisez le motif de modèle Chose curieuse Récurrent (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; 
}; 

Notez que j'ai dû faire m_price et m_quantity public afin que la classe de base peut y accéder. Vous ne voulez probablement pas faire cela, vous devrez donc soit ajouter des accesseurs publics (ou utiliser ceux qui existent déjà, le cas échéant), soit les rendre des membres protégés de la classe de base (des types spécifiés par typedefs dans la classe dérivée), ou bien la classe dérivée déclare la classe de base un ami.

Si vous voulez une fonction membre getValue publique, vous pouvez l'ajouter à la classe de base et rendre l'héritage public.

0

Vous pouvez faire:

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