Supposons que je travaille sur une bibliothèque fonctionnant avec des éléments de type Item. Le principal point d'entrée est une classe comme:Implémentation de la comparaison à l'aide d'une interface générique en C++
class Worker
{
private:
SomeContainer _c;
public:
void add(const Item &i);
void doSomething();
};
La méthode doSomething()
examine les éléments ajoutés, les compare, etc., et fait quelque chose avec eux. La classe Item a donc besoin d'un operator==
.
Maintenant, je veux utiliser cette bibliothèque dans différents environnements et dans chaque environnement l'implémentation de la classe Item est différente. Par conséquent, Item nécessite une fonction de comparaison virtuelle:
class Item
{
protected:
virtual bool _equals(Item &other) = 0;
public:
bool operator==(Item &other) { return _equals(other); };
};
Chaque environnement possède sa propre implémentation Item. La bibliothèque ne connaît que la classe Item et les classes d'éléments spécifiques sont définies et implémentées dans les applications spécifiques à la plateforme utilisant la bibliothèque. Dans l'environnement A ce pourrait être:
class AItem: public Item
{
private:
bool _equals(Item &other);
std::string _member;
...
};
et dans un environnement B:
class BItem: public Item
{
private:
bool _equals(Item &other);
int _member;
...
};
Quelle est maintenant la meilleure façon de, pour chaque environnement, mettre en œuvre la comparaison pour une utilisation par la bibliothèque? _equals
étant spécifié dans la classe Item, ses implémentations d'éléments spécifiques doivent convertir other
en leur propre type.
Dans un environnement donné, différents types d'éléments ne seront pas utilisés en même temps, donc compte tenu de cette hypothèse, ce qui suit serait tri de sécurité:
bool AItem::_equals(Item &other)
{
return this->_member == static_cast<AItem &>(other)._member;
}
Mais il semble comme une solution méchant parce que il permet à un programmeur utilisant la bibliothèque d'implémenter un nouvel environnement pour casser des choses s'il ajoute des éléments de types différents au travailleur.
D'autres solutions que je peux penser sont:
- Utilisez
dynamic_cast
. - Implémentez mon propre type de RTTI en ajoutant un membre à la classe d'élément de base indiquant l'environnement. Cela peut ensuite être utilisé dans la fonction de comparaison pour voir si
other
est du même type. Pas très élégant. - Implémentez tous les types dans la bibliothèque et sélectionnez le bon en fonction d'un
#define
au moment de la compilation. Cela signifie que la bibliothèque elle-même doit être étendue pour chaque environnement. - Utilisez un travailleur sous forme de matrice.
Mais je pense qu'il doit y avoir une solution plus élégante. Peut-être quelque chose de complètement différent. Qu'est-ce que tu ferais?
Votre dernière option "Utiliser un travailleur sous-calibré" serait la solution la meilleure et la plus élégante. Il a aussi l'avantage de la meilleure performance car il évite les appels virtuels lors de la comparaison. – mmmmmmmm
Pas pertinent à votre question, mais vous ne devriez vraiment pas utiliser les noms commençant par des traits de soulignement. Les règles pour les quelques cas où ils sont légaux sont terriblement compliquées. Un trait de soulignement suivi d'une lettre majuscule ou un trait de soulignement double est toujours réservé par l'implémentation. Un trait de soulignement suivi de minuscules est réservé dans l'espace de nom global (donc techniquement légal ici, mais cela évite beaucoup de problèmes pour prendre l'habitude de ne pas utiliser de soulignement) – jalf
Ceci est une question très pertinente: seulement quelques-uns semblent se rendre compte que l'égalité n'est pas si simple. – xtofl