嗨,我一直在尝试分析以下使用操作重载的代码。
#include <iostream>
using namespace std;
#define DBG(str) cout << str << endl
class Integer {
int n;
public:
Integer(int _n) : n(_n) { DBG("A"); };
Integer(const Integer& i) : n(i.n) { DBG("B"); };
Integer& operator=(const Integer& i) { DBG("C"); n = i.n; return *this; };
Integer& operator+=(const Integer& i) { DBG("D"); n += i.n; return *this; };
friend Integer operator+(const Integer& a, const Integer& b);
friend Integer operator*(const Integer& a, const Integer& b);
friend ostream& operator<<(ostream& os, const Integer& i);
};
Integer operator+(const Integer& a, const Integer& b) {
DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
DBG("F"); return Integer(a.n * b.n);
}
ostream& operator<<(ostream& os, const Integer& i) {
DBG("G"); os << i.n; return os;
}
int main() {
Integer n1(1), n2(2);
Integer n = 5 + n1 + 2 * n2;
cout << n << endl;
}
结果是...
A // constructor called when n1 is created
A // constructor called when n2 is created
A // when is this called?
A // when is this called?
F // called when 2 * n2 is operated
A // called when Integer(a.n * b.n) is created in the multiplication function
E // called when 5 + n1 is operated
A // called when Integer(a.n + b.n) is created in the addition function
E // called when (5 + n1) + (2 * n2) is operated
A // called when Integer is created in the addition function
G // called when n is printed using cout
5 // value of n
现在最困扰我的是A的第三和第四张印刷品。在句子Integer n = 5 + n1 + 2 * n2;
中,正在创建对象n并将正确的值分配给n,因此复制构造函数应叫做?我认为应该发生的是应调用构造函数以创建(5 + n1 + 2 * n2)
的临时对象,然后将其复制到n,然后调用复制构造函数。我理解错了什么?
请您说明发生了什么?预先谢谢你。
答案 0 :(得分:6)
问题在这一行:
Integer n = 5 + n1 + 2 * n2;
对于operator+
和int
没有Integer
,但是编译器在默认情况下从int
到Integer
默默地执行了implicit conversion所有单参数构造函数都可以用作转换方法。
这是your live code(已改进)。
这是C ++的危险特性之一,因此在构造函数之前必须使用explicit
关键字。如果添加它:
explicit Integer(const Integer& i) : n(i.n) { DBG("B"); };
由于现在无法执行隐式转换并且没有operator+(int, const Integer&)
和operator*(int, const Integer&)
,编译器将报告错误。
答案 1 :(得分:3)
您的operator+
和operator*
函数接收一个const Integer&
作为参数。
计算此行(5 + n1 + 2 * n2
)5和2将自动转换为Integer
。
如果不希望它们转换,则应考虑为int
作为参数创建运算符。
编辑:您还可以使用显式构造函数。
例如:explicit Integer(int _n){...}
///感谢您的评论@ formerlyknownas_463035818
答案 2 :(得分:1)
仅当运算符的第一个参数不是为其定义运算符的目标类的对象时,才在运算符重载中使用朋友函数。
就您而言,Integer
:
Integer operator+(const Integer& a, const Integer& b) {
DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
DBG("F"); return Integer(a.n * b.n);
}
,第一个参数确实是Integer
类型的对象,它是您的目标类。您可能想要的是能够将Integer
对象与原始整数类型一起用作操作数。
将您的朋友功能签名更改为:
Integer operator+(const int& a, const Integer& b) {
DBG("E"); return Integer(a + b.n);
}
Integer operator*(const int& a, const Integer& b) {
DBG("F"); return Integer(a * b.n);
}
请注意,使用a
代替a.n
是因为当将运算符函数定义为好友时,两个操作数均作为参数传递。(与非好友运算符函数不同,第一个运算数是调用者宾语)。因此a
包含类型为int
的值,而不包含类型为Integer
的值。
对包含
DBG("A")
的构造函数的匿名调用是将5和2从int
转换为Integer
时发生隐式转换的结果。
这不可靠,尽管您的代码可能有效。 希望这会有所帮助。