C++ 如何正确重载 ostream 的 << 运算符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/476272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly overload the << operator for an ostream?
提问by Matthias van der Vlies
I am writing a small matrix library in C++ for matrix operations. However my compiler complains, where before it did not. This code was left on a shelf for 6 months and in between I upgraded my computer from debian etch to lenny (g++ (Debian 4.3.2-1.1) 4.3.2 ) however I have the same problem on a Ubuntu system with the same g++.
我正在用 C++ 编写一个用于矩阵运算的小型矩阵库。但是我的编译器抱怨,在它之前没有。这段代码被搁置了 6 个月,在此期间我将我的计算机从 debian etch 升级到 lenny (g++ (Debian 4.3.2-1.1) 4.3.2 ) 但是我在具有相同 g++ 的 Ubuntu 系统上遇到了同样的问题.
Here is the relevant part of my matrix class:
这是我的矩阵类的相关部分:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
}
}
And the "implementation":
和“实施”:
using namespace Math;
std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {
[...]
}
This is the error given by the compiler:
这是编译器给出的错误:
matrix.cpp:459: error: 'std::ostream& Math::Matrix::operator<<(std::ostream&, const Math::Matrix&)' must take exactly one argument
matrix.cpp:459: 错误:'std::ostream& Math::Matrix::operator<<(std::ostream&, const Math::Matrix&)' 必须只采用一个参数
I'm a bit confused by this error, but then again my C++ has gotten a bit rusty after doing lots of Java those 6 months. :-)
我对这个错误有点困惑,但是在这 6 个月里做了很多 Java 之后,我的 C++ 再次变得有点生疏。:-)
采纳答案by Mehrdad Afshari
You have declared your function as friend
. It's not a member of the class. You should remove Matrix::
from the implementation. friend
means that the specified function (which is not a member of the class) can access private member variables. The way you implemented the function is like an instance method for Matrix
class which is wrong.
您已将函数声明为friend
. 它不是班级的成员。您应该Matrix::
从实现中删除。friend
意味着指定的函数(不是类的成员)可以访问私有成员变量。您实现该函数的方式就像Matrix
是错误的类的实例方法。
回答by Johannes Schaub - litb
Just telling you about one other possibility: I like using friend definitions for that:
只是告诉你另一种可能性:我喜欢使用朋友定义:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
The function will be automatically targeted into the surrounding namespace Math
(even though its definition appears within the scope of that class) but will not be visible unless you call operator<< with a Matrix object which will make argument dependent lookup find that operator definition. That can sometimes help with ambiguous calls, since it's invisible for argument types other than Matrix. When writing its definition, you can also refer directly to names defined in Matrix and to Matrix itself, without qualifying the name with some possibly long prefix and providing template parameters like Math::Matrix<TypeA, N>
.
该函数将自动定位到周围的命名空间Math
(即使它的定义出现在该类的范围内),但除非您使用 Matrix 对象调用 operator<<,否则它将不可见,该对象将使参数相关查找找到该运算符定义。这有时有助于处理模棱两可的调用,因为它对于 Matrix 以外的参数类型是不可见的。在编写其定义时,您还可以直接引用 Matrix 中定义的名称和 Matrix 本身,而无需使用一些可能很长的前缀来限定名称并提供模板参数,例如Math::Matrix<TypeA, N>
.
回答by kal
To add to Mehrdad answer ,
要添加到 Mehrdad 答案,
namespace Math
{
class Matrix
{
public:
[...]
}
std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}
In your implementation
在您的实施中
std::ostream& operator<<(std::ostream& stream,
const Math::Matrix& matrix) {
matrix.print(stream); //assuming you define print for matrix
return stream;
}
回答by sanjivr
Assuming that we're talking about overloading operator <<
for all classes derived from std::ostream
to handle the Matrix
class (and not overloading <<
for Matrix
class), it makes more sense to declare the overload function outside the Math namespace in the header.
假设我们谈论过载operator <<
对源自所有类std::ostream
来处理Matrix
类(而不是重载<<
为Matrix
类),它更有意义的声明在标题中数学命名空间外的过载功能。
Use a friend function only if the functionality cannot be achieved via the public interfaces.
仅当无法通过公共接口实现功能时才使用友元函数。
Matrix.h
矩阵.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
Note that the operator overload is declared outside the namespace.
请注意,运算符重载是在命名空间之外声明的。
Matrix.cpp
矩阵.cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
On the other hand, if your overload function doesneed to be made a friend i.e. needs access to private and protected members.
另一方面,如果您的重载函数确实需要成为朋友,即需要访问私有成员和受保护成员。
Math.h
数学.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
You need to enclose the function definition with a namespace block instead of just using namespace Math;
.
您需要使用命名空间块而不是仅包含using namespace Math;
.
Matrix.cpp
矩阵.cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
回答by QuentinUK
In C++14 you can use the following template to print any object which has a T::print(std::ostream&)const; member.
在 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;
}
In C++20 Concepts can be used.
在 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;
}