it-swarm.com.de

Wie kann der Operator << für einen Ostream richtig überladen werden?

Ich schreibe eine kleine Matrixbibliothek in C++ für Matrixoperationen. Allerdings beschwert sich mein Compiler, wo es vorher nicht geschah. Dieser Code wurde für 6 Monate im Regal belassen und zwischendurch habe ich meinen Computer von Debian Etch auf Lenny (g ++ (Debian 4.3.2-1.1) 4.3.2) aktualisiert, aber ich habe das gleiche Problem auf einem Ubuntu-System mit demselben g ++ .

Hier ist der relevante Teil meiner Matrixklasse:

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
    }
}

Und die "Umsetzung":

using namespace Math;

std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {

    [...]

}

Dies ist der vom Compiler angegebene Fehler:

matrix.cpp: 459: Fehler: 'std :: ostream & Math :: Matrix :: operator << (std :: ostream &, const Math :: Matrix &)' muss genau ein Argument enthalten

Ich bin ein bisschen verwirrt von diesem Fehler, aber mein C++ ist ein bisschen verrostet, nachdem ich viele Java diese 6 Monate. :-)

221

Sie haben Ihre Funktion als friend deklariert. Es ist kein Mitglied der Klasse. Sie sollten Matrix:: Aus der Implementierung entfernen. friend bedeutet, dass die angegebene Funktion (die kein Mitglied der Klasse ist) auf private Mitgliedsvariablen zugreifen kann. Die Art und Weise, wie Sie die Funktion implementiert haben, ist wie eine Instanzmethode für die Klasse Matrix, die falsch ist.

119
Mehrdad Afshari

Ich erzähle Ihnen nur eine andere Möglichkeit: Ich verwende dafür gerne Freundesdefinitionen:

namespace Math
{
    class Matrix
    {
    public:

        [...]

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

Die Funktion wird automatisch in den umgebenden Namespace Math verschoben (auch wenn ihre Definition im Geltungsbereich dieser Klasse liegt), ist jedoch nur sichtbar, wenn Sie operator << mit einem Matrix-Objekt aufrufen, das die argumentabhängige Suche bewirkt finde diese Operatordefinition. Das kann manchmal bei mehrdeutigen Aufrufen helfen, da es für andere Argumenttypen als Matrix unsichtbar ist. Beim Schreiben der Definition können Sie auch direkt auf in Matrix definierte Namen und auf Matrix selbst verweisen, ohne den Namen mit einem möglicherweise langen Präfix zu versehen und Vorlagenparameter wie Math::Matrix<TypeA, N> Anzugeben.

134

Um Mehrdad Antwort hinzuzufügen,

namespace Math
{
    class Matrix
    {
       public:

       [...]


    }   
    std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}

In Ihrer Implementierung

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

Angenommen, wir sprechen von einer Überladung von operator << Für alle von std::ostream Abgeleiteten Klassen, um die Klasse Matrix zu behandeln (und nicht von einer Überladung von << Für Matrix Klasse) ist es sinnvoller, die Überladungsfunktion außerhalb des Math-Namespace im Header zu deklarieren.

Verwenden Sie eine Friend-Funktion nur, wenn die Funktionalität nicht über die öffentlichen Schnittstellen erreicht werden kann.

Matrix.h

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

Beachten Sie, dass die Operatorüberladung außerhalb des Namespaces deklariert wird.

Matrix.cpp

using namespace Math;
using namespace std;

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

Auf der anderen Seite, wenn Ihre Überladungsfunktion gemacht werden muss , muss ein Freund, d. H. Zugriff auf private und geschützte Mitglieder.

Math.h

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

Sie müssen die Funktionsdefinition mit einem Namespace-Block anstelle von nur using namespace Math; Einschließen.

Matrix.cpp

using namespace Math;
using namespace std;

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

In C++ 14 können Sie die folgende Vorlage verwenden, um jedes Objekt zu drucken, das eine T :: print (std :: ostream &) const; Mitglied.

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