Hoe de << operator voor een ostream?

Ik schrijf een kleine matrixbibliotheek in C++ voor matrixbewerkingen. Maar mijn compiler klaagt, waar voorheen niet. Deze code bleef 6 maanden op een plank liggen en tussendoor heb ik mijn computer geüpgraded van debian etch naar lenny (g++ (Debian 4.3.2-1.1) 4.3.2
) maar ik heb hetzelfde probleem op een Ubuntu-systeem met dezelfde g++.

Hier is het relevante deel van mijn matrixles:

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

En de “implementatie”:

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

Dit is de fout die door de compiler wordt gegeven:

matrix.cpp:459: fout: ‘std::ostream&
Wiskunde::Matrix::operator<<(std::ostream&,
const Math::Matrix&)’ moet nemen
precies één argument

Ik ben een beetje in de war door deze fout, maar nogmaals, mijn C++ is een beetje roestig geworden nadat ik die 6 maanden veel Java had gedaan. 🙂


Antwoord 1, autoriteit 100%

Je hebt je functie als friendaangegeven. Het is geen lid van de klas. U moet Matrix::uit de implementatie verwijderen. friendbetekent dat de gespecificeerde functie (die geen lid is van de klasse) toegang heeft tot private lidvariabelen. De manier waarop je de functie hebt geïmplementeerd, is als een instantiemethode voor de klasse Matrixdie verkeerd is.


Antwoord 2, autoriteit 97%

Gewoon vertellen over een andere mogelijkheid: ik hou van het gebruik van vrienddefinities daarvoor:

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

De functie wordt automatisch gericht op de omringende naamruimte Math(hoewel de definitie ervan verschijnt binnen de reikwijdte van die klasse), maar niet zichtbaar is tenzij u operator & lt; & lt; Met een MATRIX-object dat de afhankelijke opzoeking van het argument zal maken, vindt u dat de definitie van de operator. Dat kan soms helpen met dubbelzinnige gesprekken, omdat het onzichtbaar is voor andere argumenten dan matrix. Bij het schrijven van de definitie kunt u ook rechtstreeks naar namen verwijzen in Matrix en op Matrix zelf, zonder de naam te kwalificeren met een aantal mogelijk lange voorvoegsel en het verschaffen van sjabloonparameters zoals Math::Matrix<TypeA, N>.


Antwoord 3, Autoriteit 62%

Om toe te voegen aan MEHRDAD-antwoord,

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

In uw implementatie

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

Antwoord 4, Autoriteit 54%

Ervan uitgaande dat we het hebben over het overbelasten van de operator <<voor alle klassen afgeleid van std::ostreamom de Matrixte verwerken class (en niet <<voor Matrixclass te overbelasten), is het logischer om de overload-functie buiten de Math-naamruimte in de koptekst te declareren.

Gebruik alleen een vriendenfunctie als de functionaliteit niet kan worden bereikt via de openbare interfaces.

Matrix.h

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

Houd er rekening mee dat de overbelasting van de operator buiten de naamruimte wordt gedeclareerd.

Matrix.cpp

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

Aan de andere kant, als je overbelastingsfunctie welbevriend moet worden, d.w.z. toegang nodig heeft tot privé- en beschermde leden.

Math.h

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

Je moet de functiedefinitie omsluiten met een naamruimteblok in plaats van alleen using namespace Math;te gebruiken.

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;
    }                 
}

Antwoord 5, autoriteit 33%

In C++14 kunt u de volgende sjabloon gebruiken om elk object met een T::print(std::ostream&)const; lid.

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

In C++20 kunnen concepten worden gebruikt.

template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
    { t.print(os) };
};
template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) { 
    t.print(os); 
    return os; 
} 

Antwoord 6

Ik zou dit een beetje willen vereenvoudigen met een voorbeeld dat <<overbelast om een array af te drukken.

  1. Geef eerst beide objecttypen rond de operator <<
  2. maak als volgt een functie om de operator te overbelasten.
#include<iostream> 
using namespace std;
void operator<<(ostream& os, int arr[]) {
    for (int i = 0;i < 10;i++) {
        cout << arr[i] << " ";
    }
    cout << endl; 
}
int main() {
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    cout << arr;
}

als trapsgewijze operatoren ook vereist zijn, zorg er dan voor dat u coutobject retourneert
in de overbelaste functie als volgt,

#include<iostream> 
using namespace std;
ostream& operator<<(ostream& os, int arr[]) {
    for (int i = 0;i < 10;i++) {
        cout << arr[i] << " ";
    }
    cout << endl; 
    return os;
}
int main() {
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 11,22,33,44,55,66,77,88,99,100 };
    // cascading of operators
    cout << arr << arr2;
}

Other episodes