我正在用c++编写一个用于矩阵运算的小型矩阵库。然而,我的编译器抱怨,以前它没有。这段代码被搁置了6个月,在此期间,我把我的电脑从debian etch升级到lenny (g++ (debian 4.3.2-1.1) 4.3.2 ),但是我在Ubuntu系统上也遇到了同样的问题。

这是我的矩阵类的相关部分:

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:错误:` std::ostream& 数学:矩阵::操作符< < (std::上ostream, const Math::Matrix&)'必须取 只有一个参数

我对这个错误有点困惑,但在这6个月做了很多Java之后,我的c++已经有点生疏了。: -)


当前回答

再加上迈赫达的回答,

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

其他回答

你已经表明了你作为朋友的职责。它不是这个类的成员。您应该从实现中删除Matrix::。Friend表示指定的函数(不是类的成员)可以访问私有成员变量。你实现函数的方式就像一个矩阵类的实例方法,这是错误的。

假设我们讨论的是对std::ostream派生的所有类重载操作符<<来处理Matrix类(而不是对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&);
    };
}

您需要将函数定义包含在一个名称空间块中,而不是仅仅使用名称空间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;
    }                 
}

我想用一个重载<<来打印数组的例子来简化一下。

首先将两个对象类型传递给<<操作符 创建一个函数来重载操作符,如下所示。

#include<iostream> 
using namespace std;

void operator<<(ostream& os, int arr[]) {
    for (int i = 0;i < 10;i++) {
        os << arr[i] << " ";
    }
    os << endl; 
}
    
int main() {
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    cout << arr;
}

如果还需要级联操作符,请确保返回cout对象 在重载函数中,

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

再加上迈赫达的回答,

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

在c++ 14中,你可以使用下面的模板来打印任何具有T::print(std::ostream&)const;成员。

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

在c++ 20中可以使用概念。

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