2009-10-12 5 views
3

J'ai un vecteur d'objets d'étudiants que je veux trier en utilisant #include <algorithm> et sort(list.begin(), list.end());problème de surcharge l'opérateur <en C++

Pour ce faire, je comprends que je dois surcharger l'opérateur « < » mais après essayer (et échouer) avec plusieurs méthodes suggérées en ligne, je suis à court d'idées.

Voici ma dernière tentative:

En Student.h ...

... 
using namespace std; 
class Student 
{ 
    friend bool operator <(const Student& first, const Student& second); 
    public: 
    ... 
    private: 
    ... 
}; 

Et Student.cpp ...

... 
#include "Student.h" 
using namespace std; 
... 
bool operator <(const Student& first, const Student& second) 
{ 
    return first.Name() < second.Name(); 
} 

où "Nom()" est une fonction constante qui renvoie une chaîne.

Le programme compile et fonctionne, mais ma fonction de l'opérateur est jamais appelé pendant le tri et quand j'essayé comparer deux objets étudiants comme s1 < s2 je me suis une « erreur: opérateur surchargé introuvable »

Comment puis-je surcharge correctement cet opérateur afin que mon genre fonctionne comme je l'ai l'intention?

Répondre

6

Je n'utiliserais pas un ami ici, et je ne suis pas sûr que cela fonctionne du tout. Ce que je voudrais utiliser est ...

class Student 
{ 
    public: 
    bool operator< (const Student& second) const; 
}; 

bool Student::operator< (const Student& second) const 
{ 
    return (Name() < second.Name()); 
} 

Notez le const arrière, ce qui indique que, dans l'opérateur <, * c'est constant.

EDIT Je ne peux pas supprimer cette réponse car elle a été acceptée, mais je le ferais si je le pouvais. Je ne peux pas non plus le remplacer par un bon. Voir le commentaire de Drew Dormanns ci-dessous, et Ross Smiths answer.

+0

Je pense que j'ai finalement décidé que c'était la réponse que je choisirais, parce que c'est celle qui m'a le plus directement amené à identifier le plus gros problème que j'avais avec mes pointeurs. –

+4

Cette approche est souvent évitée car si les types sont convertibles en Student, le code convertit le type de droite mais pas le type de gauche. Une fonction d'ami se comporterait de manière cohérente pour les deux parties. –

1

Eh bien, vous pouvez le faire comme un opérateur interne:

class Student 
{ 
    public: 
    bool operator <(const Student& second) const; 
    ... 
    private: 
    ... 
}; 

Avec une mise en œuvre comparant « ceci » à la seconde. La question que je me pose est la suivante: est-ce que la méthode 'Nom' vient dans une saveur const? Parce que si ce n'est pas le cas, vous ne pouvez pas écrire une méthode const qui l'utilise.

+0

Cela semble probable - les paramètres "premier" et "second" de la version friend étaient const. – Steve314

9

Vous n'avez pas dit quel compilateur vous utilisiez, mais je suppose que vous en utilisez un assez récent qui implémente la règle "l'ami n'est pas une déclaration". L'instruction friend à l'intérieur de la classe ne sert pas de déclaration de fonction; Les autres modules qui incluent Student.h ne voient aucune déclaration de la fonction. Il est visible uniquement dans le fichier Student.cpp. (Les anciens compilateurs n'ont pas cette règle et traitent une déclaration d'ami comme une déclaration de fonction.)

La fonction n'a pas besoin d'être un ami, car elle n'utilise aucun membre privé de la classe Student (Je suppose que Name() est public). Déplacez la déclaration de la fonction en dehors de la classe, et remplacez "ami" par "extern", et cela devrait fonctionner.

Il est possible de faire de l'opérateur une fonction membre, comme certaines affiches ci-dessus l'ont suggéré, mais ce n'est pas nécessaire. Faire des opérateurs de comparaison des fonctions membres est généralement désapprouvé, car cela signifie que les deux arguments ne sont pas traités symétriquement (l'un est l'argument invisible "this", l'autre est un argument de fonction normal), ce qui peut conduire à des résultats surprenants (par exemple, différentes conversions de type peuvent être appliquées aux arguments).

+0

Est-il nécessaire de marquer la déclaration de fonction extern? Je n'ai fait que cela avec des variables déclarées dans des fichiers d'en-tête. –

+0

Il était difficile de décider d'une seule réponse pour celui-ci. Mes tentatives initiales ont toutes été définies au sein de la classe et j'ai seulement essayé la version "ami" en désespoir de cause après avoir lu la déclaration de quelqu'un que "trier" ne serait pas effectué à moins que vous ne le fassiez. Il s'est avéré que j'avais aussi un problème lié au pointeur. –

+0

Certes, ce n'est pas vraiment nécessaire; les fonctions en dehors des classes ont une liaison externe par défaut. J'ai l'habitude de le mettre pour indiquer au lecteur que la fonction est définie dans un autre fichier source (par opposition à être une déclaration avant d'une fonction définie ailleurs dans le même fichier). –

2

Par ailleurs, une fonction de ce simple Personnellement, je tout simplement le faire, à moins que le guide de style interdit la définition des fonctions à l'intérieur des définitions de classe:

class Student 
{ 
    friend bool operator <(const Student& first, const Student& second) 
    { 
     return first.Name() < second.Name(); 
    } 
    ... 
}; 

Cette forme de la déclaration « ami » vous permet de définir un non-membreoperator< à l'intérieur du corps de la classe. C'est toujours un ami, donc Name() peut être privé si désiré.