为什么运算符重载需要引用?
Why is a reference needed in operator overloading?
在什么情况下重载时需要引用,因为没有它代码仍然有效?我知道它与链接有关,但我不明白为什么需要引用。
示例:
Object& operator++();
如果没有 'reference',运算符函数将 return by value - 这将是一个 copy 原始对象 - 这不是预期的。
例如,在使用和不使用 'reference' 的情况下尝试以下代码,您将看到最终 one.show()
调用的不同结果:
#include <iostream>
class myInt {
private:
int value;
public:
myInt() : value{ 0 } { }
myInt(int x) : value{ x } { }
// myInt operator ++() { ++value; return *this; }
myInt& operator ++() { ++value; return *this; }
void show() {
std::cout << value << std::endl;
}
};
int main(int argc, char* argv[])
{
myInt one(1);
one.show();
myInt two = ++(++one);
two.show();
one.show(); // Difference shows here!
return 0;
}
这是因为,在没有引用的情况下,括号外的 ++
对 one
对象的本地创建的 copy 进行操作。
内置一元运算符 ++ return是对应用该运算符的对象的引用。
例如你可以这样写
int i = 10;
++++i;
因此,要模拟相同的行为,用户定义的运算符也应该 return 对象的引用。
所以你可以这样写:x = i++;
我认为不需要它;它通常只是以这种方式使用,它可能会导致假设运算符 return 和 value/reference 的代码出现问题 - 在这种情况下,如果它,您将无法在该代码中使用您的对象return 没有合适的值。此外,如果操作员做出他们不期望的奇怪事情,其他程序员可能会发现您的代码具有误导性。
注意:某些类型 return 对象的副本而不是引用:i++
(旧 val 的副本)与 ++i
(新值)。
让我们看看您的示例 - 我们可能希望将同一对象增加两次,因此,我们可能希望执行以下操作:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject& operator++()
{
++cnt;
return *this;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
在这种情况下,我们使用链接将计数器增加两次,正如我们预期的那样,我们得到以下结果:
The value at start 0
The value after increment 1
The value after two increments in the same time: 3
如果我们应该 return 一个对象而不是对 this 的引用,那么,我们对左值引用进行操作(因为这个对象没有一个名字!),因此,此链接将对原始对象无任何作用,如以下示例所示:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject(const MyObject& other)
{
this->cnt = other.cnt;
}
MyObject operator++()
{
MyObject tmp(*this);
++cnt;
return tmp;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
输出:
The value at start 0
The value after increment 1
The value after two increments in the same time: 2
在什么情况下重载时需要引用,因为没有它代码仍然有效?我知道它与链接有关,但我不明白为什么需要引用。
示例:
Object& operator++();
如果没有 'reference',运算符函数将 return by value - 这将是一个 copy 原始对象 - 这不是预期的。
例如,在使用和不使用 'reference' 的情况下尝试以下代码,您将看到最终 one.show()
调用的不同结果:
#include <iostream>
class myInt {
private:
int value;
public:
myInt() : value{ 0 } { }
myInt(int x) : value{ x } { }
// myInt operator ++() { ++value; return *this; }
myInt& operator ++() { ++value; return *this; }
void show() {
std::cout << value << std::endl;
}
};
int main(int argc, char* argv[])
{
myInt one(1);
one.show();
myInt two = ++(++one);
two.show();
one.show(); // Difference shows here!
return 0;
}
这是因为,在没有引用的情况下,括号外的 ++
对 one
对象的本地创建的 copy 进行操作。
内置一元运算符 ++ return是对应用该运算符的对象的引用。
例如你可以这样写
int i = 10;
++++i;
因此,要模拟相同的行为,用户定义的运算符也应该 return 对象的引用。
所以你可以这样写:x = i++;
我认为不需要它;它通常只是以这种方式使用,它可能会导致假设运算符 return 和 value/reference 的代码出现问题 - 在这种情况下,如果它,您将无法在该代码中使用您的对象return 没有合适的值。此外,如果操作员做出他们不期望的奇怪事情,其他程序员可能会发现您的代码具有误导性。
注意:某些类型 return 对象的副本而不是引用:i++
(旧 val 的副本)与 ++i
(新值)。
让我们看看您的示例 - 我们可能希望将同一对象增加两次,因此,我们可能希望执行以下操作:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject& operator++()
{
++cnt;
return *this;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
在这种情况下,我们使用链接将计数器增加两次,正如我们预期的那样,我们得到以下结果:
The value at start 0
The value after increment 1
The value after two increments in the same time: 3
如果我们应该 return 一个对象而不是对 this 的引用,那么,我们对左值引用进行操作(因为这个对象没有一个名字!),因此,此链接将对原始对象无任何作用,如以下示例所示:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject(const MyObject& other)
{
this->cnt = other.cnt;
}
MyObject operator++()
{
MyObject tmp(*this);
++cnt;
return tmp;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
输出:
The value at start 0
The value after increment 1
The value after two increments in the same time: 2