2009-08-17 7 views
2

J'ai une structure pour laquelle je veux définir un ordre relatif en définissant <,>, < = et> = opérateurs. En fait, dans ma commande, il n'y aura pas d'égalité, donc si une structure n'est pas plus petite qu'une autre, elle est automatiquement plus grande.comment faire référence à la structure actuelle dans un opérateur surchargé?

J'ai défini le premier opérateur comme celui-ci:

struct MyStruct{ 
... 
... 

bool operator < (const MyStruct &b) const {return (somefancycomputation);} 

}; 

maintenant je voudrais définir les autres opérateurs en fonction de cet opérateur, de sorte que < = retournera les mêmes que < et les deux autres seront tout simplement retourner l'oposite. donc par exemple pour l'opérateur> je voudrais écrire quelque chose comme

bool operator > (const MyStruct &b) const {return !(self<b);} 

mais je ne sais pas comment Référé à ce « moi » car je ne peux que refere aux champs à l'intérieur du struct actuel.

tout est en C++

espère que ma question était compréhensible :)

merci pour l'aide!

+2

Êtes-vous est-ce que vous voulez que '<=' retourne la même chose que '<'? Je recommanderais généralement contre. Avoir 'a <= b' identiquement égal à'! (B b' identiquement égal à 'b

+4

Habituellement, on définit les opérateurs binaires comme des fonctions libres et non comme des membres. Cela permet d'obtenir le même comportement pour les deux arguments lorsque des conversions implicites entrent en jeu; avoir des conversions implicites sur le second mais pas sur le premier est perturbant. – AProgrammer

Répondre

10

Auto est *this.

En d'autres termes, this est un pointeur vers l'objet actuel, vous devez donc le déréférencer pour obtenir l'objet réel.

+1

@genesys Expansion sur le point de Dave, vous voudrez écrire votre code comme quelque chose comme "opérateur booléen> (const MyStruct & b) const {return! ((* Ceci) Glen

+1

Upvoted. Une autre possibilité consiste à créer une fonction qui compare deux structures A et B. – mcandre

1

Opérateur surchargé est juste une fonction de membre mais avec une syntaxe de fantaisie. Vous pouvez appeler explicitement comme ceci:


this->operator<(b); 

ou vous sauver quelques cheveux :) et simplement fournir int compare(const MyStruct&) fonction membre et l'utiliser dans tous les opérateurs de comparaison non-membres.

+0

Oui, fournir une fonction nommée et la réutiliser est une approche beaucoup plus lisible. – sharptooth

1

Ceci est un pointeur vers votre objet actuel. Donc (comme le dit @Dave Hinton), vous devrez le déréférencer. Mais, theres une autre option

Deux options:

return !(*this<b) 

or 

return (!this->operator<(b)) 

Oui, le premier est tout à fait agréable.

1

effectivement dans ma commande il n'y aura pas d'égalité, donc si une structure n'est pas plus petite qu'une autre, elle est automatiquement plus grande.

C'est un problème. Les opérations C++ (et de nombreux algorithmes) nécessitent un strict weak ordering, ce qui (entre autres) implique que x == x est valable pour tout x. De manière plus générale:

not (x < y) and not (y < x) 

implique

x == y 

pour tout x et y. En d'autres termes: vous avez probablement devez définir une sorte d'égalité pour que votre structure fonctionne avec n'importe quel algorithme conventionnel.

+0

Beaucoup de choses vont encore fonctionner, cependant, avec certaines conditions. 'std :: sort' fonctionnera, bien que vous n'ayez naturellement aucun contrôle sur les ordres de valeurs" équivalentes ". Vous pouvez toujours avoir 'set' et' map', mais naturellement, une fois que vous avez une valeur, vous ne pouvez pas placer une entrée "équivalente" dans la collection (mais vous pouvez utiliser 'multiset' et' multimap'). Des choses comme 'find' et' equal_range' sont condamnées. –

+1

Une chaîne * faible * qui commande, n'implique pas un ordre total, ou une équivalence (par ordre) n'implique pas l'égalité. Autrement dit, not (x

+1

@Charles, ne signifie pas "faible" que deux éléments peuvent être équivalents en ce qui concerne la commande? Je pense que ce dont vous avez parlé est appelé «ordre partiel» et non «ordre faible»? –

6

Si vous fournissez un operator< avec toute la logique appropriée alors (qu'il soit ou non implémenté en tant que fonction libre) vous pouvez implémenter les autres opérateurs comme des fonctions libres. Ceci suit la règle consistant à préférer les non-membres aux membres, lorsque cela est possible, et les fonctions libres auront un comportement identique. conversions des opérandes gauche et droit, alors que les opérateurs implémentés comme fonctions membres ne le font pas.

par exemple.

inline bool operator>(const MyStruct& a, const MyStruct&b) 
{ 
    return b < a; 
} 

inline bool operator<=(const MyStruct& a, const MyStruct&b) 
{ 
    return !(b < a); 
} 

inline bool operator>=(const MyStruct& a, const MyStruct&b) 
{ 
    return !(a < b); 
} 
+0

Une autre publication que j'aimerais avoir 10 votes à donner ... Et je voudrais ajouter que 'operator <', étant un opérateur binaire qui traite ses deux arguments de la même façon (il les laisse seuls), habituellement devrait également être mis en œuvre en tant que non-membre. – sbi

+0

je vous remercie pour votre réponse .. Je suis désolé pour la question noob, mais pourriez-vous aussi m'expliquer quelle est la différence entre les non-membres et les membres et pourquoi préférer le premier ?? merci :) –

0

Je suis avec Tom/Dave ci-dessus en ce que la manière directe d'écrire ceci:

return !(*this<b); 

mais pour moi la forme la plus explicitement clair:

return !operator<(b); 

et Tom : return! (this-> opérateur < (b)); semble un peu idiot.

Ce petit peu méchant C code préprocesseur (j'ai aussi une meilleure mais plus une solution de modèle technique):

#define CREATE_SYMETRIC_ORDINAL_OPERATORS(Type) \ 
int operator !=(Type X) {return !((*this)==X); } \ 
int operator <(Type X) {return !((*this)>=X); } \ 
int operator >=(Type X) {return (((*this)>X)||((*this)==X)); } \ 
int operator <=(Type X) {return (((*this)<X)||((*this)==X)); } 

définit automatiquement tous les opérateurs de comparaison en supposant == et> sont définis comme ceci:

class Comparable { 
    public: 
    int operator ==(Comparable B); 
    int operator >(Comparable B); 
    CREATE_SYMETRIC_OPERATORS(Comparable); 
}; 
+0

Cet ensemble de macros me donne un peu les squicks j'ai peur. –

+0

Oui, je n'ai jamais aimé non plus et l'ai remplacé par un héritage simple d'une classe qui a == et Elemental

+0

@Elemental: Vous pouvez obtenir les deux (simplicité et rapidité) en utilisant le CRTP. Aussi, il est probablement préférable de baser la comparaison sur 'operator <()' car c'est celui qui est habituellement ('std :: map',' std :: sort' etc.) requis. Enfin, IMO vaut mieux prendre l'argument RHS par référence const, car l'optimiseur peut échouer à empêcher la copie d'un type cher à copier. Puisque c'est trop grand pour un commentaire, je vais ajouter ma propre réponse en montrant cela. – sbi

2

C'est conçu comme une légère amélioration par rapport Element's answer:

template< class Derived > 
class Comparable { 
    public: 
    bool operator !=(const Derived& rhs) const 
    {return !(static_cast<Derived&>(*this) == rhs); } 

    bool operator <(const Derived& rhs) const 
    {return rhs < static_cast<Derived&>(*this); } 

    bool operator >=(const Derived& rhs) const 
    {return !(static_cast<Derived&>(*this) < rhs); } 

    bool operator <=(const Derived& rhs) const 
    {return !(static_cast<Derived&>(*this) > rhs); } 
}; 

struct MyStruct : public Comparable<MyStruct> { 
    bool operator ==(const MyStruct & rhs) const 
    {return /* whatever */; } 

    bool operator <(const MyStruct & rhs) const 
    {return /* whatever */; } 
}; 
Questions connexes