Как правильно перегрузить оператор << для streamа?

Я пишу небольшую матричную библиотеку в C ++ для матричных операций. Однако мой компилятор жалуется, где раньше этого не было. Этот код остался на полке в течение 6 месяцев, а между мной я обновил свой компьютер от debian etch до lenny (g ++ (Debian 4.3.2-1.1) 4.3.2), однако у меня такая же проблема для системы Ubuntu с тем же g ++ ,

Вот соответствующая часть моего матричного classа:

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

И «реализация»:

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

Это ошибка, заданная компилятором:

matrix.cpp: 459: error: ‘std :: ostream & Math :: Matrix :: operator << (std :: ostream &, const Math :: Matrix &)' должен принимать ровно один аргумент

Я немного смущен этой ошибкой, но опять же мой C ++ получил немного ржавый, после того, как многие Java за эти 6 месяцев. 🙂

    Вы заявили о своей функции как friend . Это не член classа. Вы должны удалить Matrix:: из реализации. friend означает, что указанная функция (которая не является членом classа) может обращаться к частным переменным-членам. Способ, которым вы реализовали функцию, похож на метод экземпляра classа Matrix который является неправильным.

    Просто расскажу вам о другой возможности: мне нравится использовать определения друзей для этого:

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

    Функция будет автоматически нацелена на окружающее пространство имен Math (хотя его определение появляется в пределах области действия этого classа), но не будет видно, если вы не вызываете оператор << с объектом Matrix, который заставит зависящий от зависимостей поиск найти это определение оператора. Иногда это может помочь с неоднозначными вызовами, поскольку оно невидимо для типов аргументов, отличных от Matrix. При написании своего определения вы также можете напрямую ссылаться на имена, определенные в матрице и на матрицу, без определения имени с некоторым возможно длинным префиксом и предоставления параметров шаблона, таких как Math::Matrix .

    Чтобы добавить к Мехридаду ответ,

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

    В вашей реализации

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

    Предполагая, что мы говорим о перегрузке operator << для всех classов, полученных из std::ostream для обработки classа Matrix (а не для перегрузки << для classа Matrix ), имеет смысл объявить функцию перегрузки вне пространства имен Math в заголовок.

    Используйте функцию друга только в том случае, если функциональность не может быть достигнута через общедоступные интерфейсы.

    Matrix.h

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

    Обратите внимание, что перегрузка оператора объявляется вне пространства имен.

    Matrix.cpp

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

    С другой стороны, если ваша функция перегрузки должна быть сделана другом, она нуждается в доступе к частным и защищенным членам.

    math.h

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

    Вы должны приложить определение функции блоком пространства имен, а не просто using namespace Math; ,

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

    В C ++ 14 вы можете использовать следующий шаблон для печати любого объекта, который имеет T :: print (std :: ostream &) const; член.

     template auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os) { t.print(os); return os; } 
    Давайте будем гением компьютера.