‚Freund‘ Funktionen und << Betreiber Überlastung: Was ist der richtige Weg, um einen Operator für eine Klasse zu überlasten?
-
26-09-2019 - |
Frage
In einem Projekt arbeite ich an, ich habe eine Score
Klasse, wie unten definiert in score.h
. Ich versuche, es so zu überlasten, wenn ein <<
Betrieb auf sie durchgeführt wird, _points + " " + _name
gedruckt wird.
Hier ist, was ich versucht zu tun:
ostream & Score::operator<< (ostream & os, Score right)
{
os << right.getPoints() << " " << right.scoreGetName();
return os;
}
Hier sind die Fehler zurückgegeben:
score.h(30) : error C2804: binary 'operator <<' has too many parameters
(Dieser Fehler erscheint 4 mal, tatsächlich)
schaffte ich es zum Laufen zu bringen, indem die Überlastung als Freund Funktion erklärt:
friend ostream & operator<< (ostream & os, Score right);
Und das Entfernen des Score::
aus der Funktionsdeklaration in score.cpp (effektiv nicht als Mitglied erklärt).
Warum funktioniert das, aber das ehemalige Stück Code nicht?
Vielen Dank für Ihre Zeit!
Bearbeiten
Ich löschte alle auf die Überlastung erwähnen auf der Header-Datei ... aber ich bekomme den folgenden (und einzigen) Fehler. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion)
Wie kommt mein Test, in main () kann nicht über die entsprechende Überlastung finden? (Es ist nicht das enthält, überprüfte ich)
Im Folgenden finden Sie den vollen score.h
#ifndef SCORE_H_
#define SCORE_H_
#include <string>
#include <iostream>
#include <iostream>
using std::string;
using std::ostream;
class Score
{
public:
Score(string name);
Score();
virtual ~Score();
void addPoints(int n);
string scoreGetName() const;
int getPoints() const;
void scoreSetName(string name);
bool operator>(const Score right) const;
private:
string _name;
int _points;
};
#endif
Lösung
Hinweis: Sie könnten auf dem Betreiber Überlastung FAQ zu suchen.
Binäre Operatoren können entweder Mitglieder ihrer linken Argument der Klasse oder kostenlose Funktionen sein. (Einige Betreiber, wie Zuordnung, müssen Mitglieder sein.) Da der Stream Betreiber linke Argument ein Strom ist, Strom Betreiber entweder Mitglieder der Stream-Klasse oder kostenlose Funktionen sein. Die kanonische Weise operator<<
für jede Art zu implementieren, ist dies:
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// stream obj's data into os
return os;
}
Beachten Sie, dass es nicht eine Elementfunktion. Beachten Sie auch, dass es die Aufgabe übernimmt pro const
Bezug zu streamen. Das ist, weil du nicht das Objekt, um kopieren wollen, dass es zu streamen und Sie nicht möchten, dass das Streaming es entweder zu verändern.
Manchmal möchten Sie Objekte, deren Interna streamen nicht zugänglich sind durch ihre Klasse öffentliche Schnittstelle, so kann der Bediener nicht an ihnen. Dann haben Sie zwei Möglichkeiten: Entweder ein öffentliches Mitglied in die Klasse setzen, die funktioniert das Streaming
class T {
public:
void stream_to(std::ostream&) const {os << obj.data_;}
private:
int data_;
};
und Anruf, dass vom Betreiber:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
obj.stream_to(os);
return os;
}
oder den Betreiber macht ein friend
class T {
public:
friend std::ostream& operator<<(std::ostream&, const T&);
private:
int data_;
};
so, dass es die Klasse private Teile zugreifen können:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
os << obj.data_;
return os;
}
Andere Tipps
Angenommen, Sie haben einen Operator Überlastung für +
schreiben wollte, so dass Sie zwei Score
Objekte zueinander hinzufügen könnte, und ein anderer, damit Sie eine int
zu einem Score
hinzufügen könnte, und ein drittes, so dass Sie eine Score
zu einem int
hinzufügen könnte. Diejenigen, die ein Score
die ersten Parameter können Elementfunktionen Score sein. Aber die, wo ein int
der erste Parameter ist, kann nicht Mitglied Funktionen von int
worden, nicht wahr? Um Ihnen dabei zu helfen, sind Sie erlaubt, sie als freie Funktionen zu schreiben. Das ist, was mit diesem <<
Betreiber geschieht, können Sie keine Member-Funktion ostream
hinzufügen, so dass Sie eine kostenlose Funktion schreiben. Das ist, was es bedeutet, wenn Sie den Score::
Teil wegzunehmen.
Nun, warum hat es eine friend
sein? Es funktioniert nicht. Sie anrufen nur öffentliche Methoden (getPoints
und scoreGetName
). Sie sehen eine Menge Freund Betreiber, da sie direkt auf die privaten Variablen sprechen mögen. Es ist in Ordnung von mir, das zu tun, weil sie von der Person maintaing die Klasse geschrieben und gepflegt. Nur nicht den Freund Teil mit dem Element-Funktion-vs-Freifunktionsteil sich verfahren werden.
Sie sind immer Fehler Kompilation wenn operator<<
eine Member-Funktion in dem Beispiel, weil Sie eine operator<<
erstellen, von einer Score
als ersten Parameter übernimmt (das Objekt der Methode des auf genannt wird), und dann einen zusätzlichen Parameter geben am Ende.
Wenn Sie einen binären Operator sind aufrufen, die als Mitglied Funktion deklariert ist, ist die linke Seite des Ausdrucks das Objekt die Methode der aufgerufen wird. z.B. a + b
Macht funktioniert wie folgt:
A a;
B b
a.operator+(b)
Es ist typischerweise bevorzugt Nichtmitglied binäre Operatoren (und in einigen Fällen zu verwenden - zum Beispiel operator<<
for ostream
ist der einzige Weg, es zu tun in diesem Fall a + b
funktionieren könnte wie folgt aus:.
A a;
B b
operator+(a, b);
Hier ist ein vollständiges Beispiel in beiden Richtungen, es zu tun ist; main () ausgeben wird '55' dreimal:
#include <iostream>
struct B
{
B(int b) : value(b) {}
int value;
};
struct A
{
A(int a) : value(a) {}
int value;
int operator+(const B& b)
{
return this->value + b.value;
}
};
int operator+(const A& a, const B& b)
{
return a.value + b.value;
}
int main(int argc, char** argv)
{
A a(22);
B b(33);
std::cout << a + b << std::endl;
std::cout << operator+(a, b) << std::endl;
std::cout << a.operator+(b) << std::endl;
return 0;
}