为什么重载的“<<”和“++”不能一起工作?
Why don't overloaded "<<" and "++" work together?
首先,我对 C++ 和 OOP 还很陌生,很抱歉问了一些愚蠢的问题。所以,在这里,我重载了“<<”和“++”(后缀和前缀),它们单独工作得很好。但是它们在组合时似乎不起作用。我不明白为什么,++-s return 都是 foo 类型的对象,所以我认为“<<”应该可以正常工作...
#include <iostream>
using namespace std;
class foo
{
int x;
public:
foo()
{
x=10;
}
foo(const foo& f1)
{
this->x=f1.x;
cout<<"OK"; /// testing if it really works
}
foo operator ++ ()
{
++x;
return *this;
}
foo operator ++ (int)
{
x++;
return *this;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, foo& S);
};
istream& operator>>(istream& in, foo& S)
{
in>>S.x;
return in;
}
ostream& operator<<(ostream& out, foo& S)
{
out<<S.x;
return out;
}
int main()
{
foo A, B, C;
cout<<A;
//cout<<++A; //error: cannot bind non-const lvalue reference of type 'foo&' to an rvalue of type 'foo'
//cout<<A++; //error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'foo')
return 0;
}
您的流输出重载应将您的 foo
引用作为 const
。毕竟,他们不应该修改传入的 foo
:
friend istream& operator<<(istream& in, const foo& S);
一个非常量引用参数(比如你的 foo& S
),必须有一个左值传递给它。由于您的增量运算符 return 是一个 r 值,因此您会看到编译器错误(正是这样说的)。为了能够同时获取 l 和 r 值,您需要更改上面的 const-reference 参数。
此外,您的 prefix 递增运算符应 return 引用:
foo& operator ++ ()
{
++x;
return *this;
}
有关重载的基本规则和习语的更多信息,请阅读此处:
除了scohe001的回答,你的后缀和前缀运算符也需要更正。
前缀运算符应该 return 对正在递增的对象的引用。您正在 return 复制 *this
。你的 return 类型应该是 foo&
这样的:
foo& operator ++ ()
{
++x;
return *this;
}
而在后缀运算符中,首先需要记住对象的状态,即在修改前制作对象的副本,然后修改对象,最后return未修改的副本,如这个:
foo operator ++ (int)
{
foo temp(*this);
++x;
return temp;
}
这是您的代码,已修复。我在更改的地方添加了评论。
#include <iostream>
using namespace std;
class foo {
int x;
public:
foo() { x = 10; }
foo(const foo& f1) {
this->x = f1.x;
cout << "OK"; /// testing if it really works
}
// Changed return type
foo& operator++() {
++x;
return *this;
}
// Re-wrote body
foo operator++(int) {
foo tmp = *this;
++(*this);
return tmp;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, const foo& S); // Added const
};
istream& operator>>(istream& in, foo& S) {
in >> S.x;
return in;
}
// Matched added const
ostream& operator<<(ostream& out, const foo& S) {
out << S.x;
return out;
}
int main() {
foo A, B, C;
cout << A << '\n';
cout << ++A << '\n';
cout << A++ << '\n';
return 0;
}
前缀 ++ 和后缀 ++ 的行为不同。这是在定期 int
.
测试运算符时观察到的
int x = 5;
std::cout << x++ << '\n';
std::cout << ++x << '\n';
你得到输出:
5
7
后缀增加 returns 原始 值,但仍然增加。前缀增量 returns 增量值。这就是为什么 prefix 需要 return 引用的原因。它 return 是它自己,我们通过引用来做到这一点。
所以在上面的短代码示例中发生的事情是 x
有它的原始值 (5) returned,但是后缀增量仍然递增,所以 x
有一个值6. 然后前缀 print 确保递增的 x
被 returned 并打印 7.
对 operator<<()
的更改是惯例。打印一个对象时,我不想修改它,所以我把它作为一个引用传递给const。
首先,我对 C++ 和 OOP 还很陌生,很抱歉问了一些愚蠢的问题。所以,在这里,我重载了“<<”和“++”(后缀和前缀),它们单独工作得很好。但是它们在组合时似乎不起作用。我不明白为什么,++-s return 都是 foo 类型的对象,所以我认为“<<”应该可以正常工作...
#include <iostream>
using namespace std;
class foo
{
int x;
public:
foo()
{
x=10;
}
foo(const foo& f1)
{
this->x=f1.x;
cout<<"OK"; /// testing if it really works
}
foo operator ++ ()
{
++x;
return *this;
}
foo operator ++ (int)
{
x++;
return *this;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, foo& S);
};
istream& operator>>(istream& in, foo& S)
{
in>>S.x;
return in;
}
ostream& operator<<(ostream& out, foo& S)
{
out<<S.x;
return out;
}
int main()
{
foo A, B, C;
cout<<A;
//cout<<++A; //error: cannot bind non-const lvalue reference of type 'foo&' to an rvalue of type 'foo'
//cout<<A++; //error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'foo')
return 0;
}
您的流输出重载应将您的 foo
引用作为 const
。毕竟,他们不应该修改传入的 foo
:
friend istream& operator<<(istream& in, const foo& S);
一个非常量引用参数(比如你的 foo& S
),必须有一个左值传递给它。由于您的增量运算符 return 是一个 r 值,因此您会看到编译器错误(正是这样说的)。为了能够同时获取 l 和 r 值,您需要更改上面的 const-reference 参数。
此外,您的 prefix 递增运算符应 return 引用:
foo& operator ++ ()
{
++x;
return *this;
}
有关重载的基本规则和习语的更多信息,请阅读此处:
除了scohe001的回答,你的后缀和前缀运算符也需要更正。
前缀运算符应该 return 对正在递增的对象的引用。您正在 return 复制 *this
。你的 return 类型应该是 foo&
这样的:
foo& operator ++ ()
{
++x;
return *this;
}
而在后缀运算符中,首先需要记住对象的状态,即在修改前制作对象的副本,然后修改对象,最后return未修改的副本,如这个:
foo operator ++ (int)
{
foo temp(*this);
++x;
return temp;
}
这是您的代码,已修复。我在更改的地方添加了评论。
#include <iostream>
using namespace std;
class foo {
int x;
public:
foo() { x = 10; }
foo(const foo& f1) {
this->x = f1.x;
cout << "OK"; /// testing if it really works
}
// Changed return type
foo& operator++() {
++x;
return *this;
}
// Re-wrote body
foo operator++(int) {
foo tmp = *this;
++(*this);
return tmp;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, const foo& S); // Added const
};
istream& operator>>(istream& in, foo& S) {
in >> S.x;
return in;
}
// Matched added const
ostream& operator<<(ostream& out, const foo& S) {
out << S.x;
return out;
}
int main() {
foo A, B, C;
cout << A << '\n';
cout << ++A << '\n';
cout << A++ << '\n';
return 0;
}
前缀 ++ 和后缀 ++ 的行为不同。这是在定期 int
.
int x = 5;
std::cout << x++ << '\n';
std::cout << ++x << '\n';
你得到输出:
5
7
后缀增加 returns 原始 值,但仍然增加。前缀增量 returns 增量值。这就是为什么 prefix 需要 return 引用的原因。它 return 是它自己,我们通过引用来做到这一点。
所以在上面的短代码示例中发生的事情是 x
有它的原始值 (5) returned,但是后缀增量仍然递增,所以 x
有一个值6. 然后前缀 print 确保递增的 x
被 returned 并打印 7.
对 operator<<()
的更改是惯例。打印一个对象时,我不想修改它,所以我把它作为一个引用传递给const。