提问人:Matthias van der Vlies 提问时间:1/25/2009 最后编辑:Peter MortensenMatthias van der Vlies 更新时间:10/9/2023 访问量:463573
如何正确地重载 ostream 的 << 运算符?[复制]
How can I properly overload the << operator for an ostream? [duplicate]
问:
我正在用C++编写一个用于矩阵运算的小型矩阵库。但是,我的编译器抱怨,以前没有。这段代码在架子上搁置了六个月,在此期间,我将计算机从 Debian 4.0 (Etch) 升级到 Debian 5.0 (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& Math::Matrix::operator<<(std::ostream&, const Math::Matrix&)' 必须取 正好一个参数
我对这个错误有点困惑,但是在这六个月做了很多Java之后,我的C++又变得有点生疏了。:-)
答:
您已将函数声明为 .它不是类的成员。您应该从实现中删除。 表示指定的函数(不是类的成员)可以访问私有成员变量。您实现该函数的方式类似于类的实例方法,这是错误的。friend
Matrix::
friend
Matrix
评论
operator<<
Math
Math
friend
补充一下 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;
}
评论
我只是告诉你另一种可能性:我喜欢使用朋友定义:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
该函数将自动定位到周围的命名空间中(即使其定义出现在该类的范围内),但除非您使用 Matrix 对象调用 operator<<否则将不可见,这将使参数相关的查找找到该运算符定义。这有时有助于处理不明确的调用,因为它对 Matrix 以外的参数类型是不可见的。在编写其定义时,您还可以直接引用 Matrix 中定义的名称和 Matrix 本身,而无需使用一些可能很长的前缀来限定名称,并提供模板参数,例如 。Math
Math::Matrix<TypeA, N>
假设我们谈论的是所有派生自的类的重载来处理类(而不是类的重载),那么在标头的 Math 命名空间之外声明重载函数更有意义。operator <<
std::ostream
Matrix
<<
Matrix
仅当无法通过公共接口实现该功能时,才使用友元函数。
矩阵.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
请注意,运算符重载是在命名空间外部声明的。
矩阵 .cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
另一方面,如果您的过载函数确实需要成为朋友,即需要访问私有和受保护的成员。
数学.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
您需要用命名空间块将函数定义括起来,而不仅仅是 .using namespace Math;
矩阵 .cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
评论
os
operator<<
在 C++14 中,您可以使用以下模板打印任何具有 T::p rint(std::ostream&)const;成员。
template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}
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;
}
评论
std::ostream&
我想用一个重载以打印数组的示例来简化这一点。<<
首先在运算符周围传递两种对象类型
<<
创建一个函数来重载运算符,如下所示。
#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;
}
评论
template<int N> ostream& operator<<(ostream& os, int(& arr)[N]) { etc
os
cout
operator==
上一个:导入模块中全局变量的可见性
下一个:前缀双冒号“::”是什么意思?
评论