Comment surcharger correctement l’opérateur pour un ostream?

J’écris une petite bibliothèque masortingcielle en C ++ pour les opérations masortingcielles. Cependant, mon compilateur se plaint, alors qu’avant il ne l’avait pas fait. Ce code a été laissé sur une étagère pendant 6 mois et entre-temps j’ai mis à niveau mon ordinateur de debian etch à lenny (g ++ (Debian 4.3.2-1.1) 4.3.2) mais j’ai le même problème sur un système Ubuntu avec le même g ++ .

Voici la partie pertinente de ma classe de masortingce:

namespace Math { class Masortingx { public: [...] friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix); } } 

Et la “mise en oeuvre”:

 using namespace Math; std::ostream& Masortingx::operator <<(std::ostream& stream, const Matrix& matrix) { [...] } 

C’est l’erreur donnée par le compilateur:

masortingx.cpp: 459: erreur: ‘std :: ostream & Math :: Masortingx :: operator << (std :: ostream &, const Math :: Matrix &)' doit prendre exactement un argument

Je suis un peu confus par cette erreur, mais là encore mon C ++ est devenu un peu rouillé après avoir fait beaucoup de Java ces 6 mois. 🙂

Vous avez déclaré votre fonction en tant friend . Ce n’est pas un membre de la classe. Vous devez supprimer Masortingx:: de l’implémentation. friend signifie que la fonction spécifiée (qui n’est pas membre de la classe) peut accéder aux variables de membre privées. La façon dont vous avez implémenté la fonction est comme une méthode d’instance pour la classe Masortingx qui est incorrecte.

Juste pour vous parler d’une autre possibilité: j’aime utiliser les définitions d’ami pour cela:

 namespace Math { class Masortingx { public: [...] friend std::ostream& operator< < (std::ostream& stream, const Matrix& matrix) { [...] } }; } 

La fonction sera automatiquement ciblée dans l'espace de noms Math (même si sa définition apparaît dans la scope de cette classe), mais ne sera visible que si vous appelez operator < < avec un objet Matrix qui rendra la recherche dépendante de l'opérateur. Cela peut parfois aider avec des appels ambigus, car il est invisible pour les types d'argument autres que Matrix. Lors de l'écriture de sa définition, vous pouvez également vous référer directement aux noms définis dans Matrix et à Matrix, sans qualifier le nom avec un préfixe éventuellement long et fournir des paramètres tels que Math::Masortingx .

Pour append à Mehrdad répondre,

 namespace Math { class Masortingx { public: [...] } std::ostream& operator< < (std::ostream& stream, const Math::Matrix& matrix); } 

Dans votre implémentation

 std::ostream& operator< <(std::ostream& stream, const Math::Matrix& matrix) { matrix.print(stream); //assuming you define print for matrix return stream; } 

En supposant que nous parlions de la surcharge de l’ operator < < pour toutes les classes dérivées de std::ostream pour gérer la classe Masortingx (sans surcharger < < pour la classe Masortingx ), il est plus logique de déclarer la fonction de surcharge en dehors de l'espace de noms Math l'en-tête.

Utilisez une fonction d'ami uniquement si la fonctionnalité ne peut pas être obtenue via les interfaces publiques.

Masortingx.h

 namespace Math { class Masortingx { //... }; } std::ostream& operator< <(std::ostream&, const Math::Matrix&); 

Notez que la surcharge de l'opérateur est déclarée en dehors de l'espace de noms.

Masortingx.cpp

 using namespace Math; using namespace std; ostream& operator< < (ostream& os, const Matrix& obj) { os << obj.getXYZ() << obj.getABC() << '\n'; return os; } 

D'un autre côté, si votre fonction de surcharge doit être créée, un ami, c'est-à-dire qu'il doit avoir access à des membres privés et protégés.

Math.h

 namespace Math { class Masortingx { public: friend std::ostream& operator< <(std::ostream&, const Matrix&); }; } 

Vous devez inclure la définition de la fonction dans un bloc d'espace de noms au lieu d' using namespace Math; simplement l' using namespace Math; .

Masortingx.cpp

 using namespace Math; using namespace std; namespace Math { ostream& operator< <(ostream& os, const Matrix& obj) { os << obj.XYZ << obj.ABC << '\n'; return os; } } 

En C ++ 14, vous pouvez utiliser le modèle suivant pour imprimer tout object possédant un const T :: print (std :: ostream &); membre.

 template auto operator< <(std::ostream& os, const T& t) -> decltype(t.print(os), os) { t.print(os); return os; }