如何正确地重载<< ostream的运营商?

时间:2009-01-24 16:34:28

标签: c++ namespaces operator-overloading iostream ostream

我正在用C ++编写一个用于矩阵运算的小型矩阵库。然而,我的编译器抱怨,在它之前没有。这段代码在架子上放置了6个月,之间我把我的电脑从debian etch升级到了lenny(g ++(Debian 4.3.2-1.1)4.3.2 但是我在具有相同g ++的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&amp;   数学::矩阵::运营商LT;≤(标准:: ostream的&安培;,   const Math :: Matrix&amp;)'必须采取   恰好一个参数

我对这个错误感到有些困惑,但是在那6个月的大量Java之后,我的C ++又变得有点生疏了。 : - )

6 个答案:

答案 0 :(得分:131)

告诉你另一种可能性:我喜欢使用朋友定义:

namespace Math
{
    class Matrix
    {
    public:

        [...]

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

该函数将自动定位到周围的命名空间Math(即使其定义出现在该类的范围内),但除非您调用operator&lt;&lt;使用Matrix对象,它将使参数依赖查找找到该运算符定义。这有时可以帮助进行模糊调用,因为除了Matrix之外的参数类型它是不可见的。在编写其定义时,您还可以直接引用Matrix和Matrix本身定义的名称,而无需使用一些可能长的前缀限定名称并提供Math::Matrix<TypeA, N>等模板参数。

答案 1 :(得分:118)

您已将自己的职能声明为friend。它不是班上的成员。您应该从实现中删除Matrix::friend表示指定的函数(不是该类的成员)可以访问私有成员变量。实现该函数的方式类似于Matrix类的实例方法,这是错误的。

答案 2 :(得分:72)

要添加到Mehrdad答案,

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

答案 3 :(得分:60)

假设我们正在讨论为operator <<派生的所有类重载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&);
    };
}

您需要使用命名空间块而不仅仅是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;
    }                 
}

答案 4 :(得分:31)

在C ++ 14中,您可以使用以下模板打印任何具有T :: print(std :: ostream&amp;)const的对象;构件。

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

答案 5 :(得分:1)

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

  1. 首先在 << 运算符周围传递两种对象类型
  2. 创建一个函数来重载运算符,如下所示。
#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;
}

如果还需要级联运算符,请确保返回 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;
}