这天逛论坛,发现了这么一个关于重载运算符的问题:
论坛问题原地址:https://bbs.csdn.net/topics/396521522?page=1#post-411413683
我对这个问题也好奇,于是自己重载了个简单的整型加法类进行分析。
首先,我创建了这样的一个类和使用实例:
#include <iostream>
#include <string>
using namespace std;
class Int {
public:
int num;
Int() {
num = 1;
cout << "默认构造" << endl;
}
Int(int var) {
num = var;
cout << "参数构造:" <<var<< endl;
}
friend Int operator + ( const Int& b, const int a) {
cout << "数值+对象" << endl;
return b.num + a;
}
friend Int operator + (const int a, const Int& b) {
cout << "数值+对象" << endl;
return b.num + a;
}
Int operator + (const Int& b) {
cout << "对象相加:"<<b.num<<"+"<<num << endl;
return b.num + num;
}
};
int main()
{
Int var1, var2, var3, var4;
var1 = var2 + 9;
var1 = 9 + var2;
var1 = 9 + 8 + 7;
var1 = var1 + var2 + var3;
var1 = var1 + 8 + var2;
var1 = 9 + var1 + 7;
cout << var1.num;
return 0;
}
通过VS给我的错误反馈,我可以看出,他都是在类对象和数值相加中出现的问题,于是,我删除了第一个友元函数,然后加了几个分行以方便后来的分析,再进行编译。
新代码:
#include <iostream>
using namespace std;
class Int {
public:
int num;
Int() {
num = 1;
cout << "默认构造" << endl;
}
Int(int var) {
num = var;
cout << "参数构造:" <<var<< endl;
}
friend Int operator + (const int a, const Int& b) {
cout << "数值+对象" << endl;
return b.num + a;
}
Int operator + (const Int& b) {
cout << "对象相加:"<<b.num<<"+"<<num << endl;
return b.num + num;
}
};
int main()
{
Int var1, var2, var3, var4;
var1 = var2 + 9;//1
cout << endl;
var1 = 9 + var2;//2
cout << endl;
var1 = 9 + 8 + 7;//3
cout << endl;
var1 = var1 + var2 + var3;//4
cout << endl;
var1 = var1 + 8 + var2;//5
cout << endl;
var1 = 9 + var1 + 7;//6
cout << var1.num;
return 0;
}
从这个运行结果图中可以分析出以下几种情形:
1.对象+对象:从左到右依次使用Int operator + (const Int& b);以进行对象相加
2.对象+数值:先对非对象进行参数构造,使其返回一个新的对象,然后再进行对象相加
3.数值+对象:使用riend Int operator + (const int a, const Int& b);以进行数值+对象,然后因为在我这次写的测试代码里的返回值的表达式结果是int型,所以会进行一次参数构造,最终返回对象。
4.数值+数值:如果没有我测试代码里的那个=号,那么这只是一次普通的int型相加,但在我的测试代码里,他会先进行完int型数值相加后,在将结果赋值给对象前,会先进行一次参数构造,然后再赋值给对象。
所以,结论如下:
1.不需要为了处理(对象+数值)这种情形,而给出一个重载运算符函数,因为编译器会对数值使用参数构造,然后,再将对象和由该数值所形成的新对象相加。
如果多给了这么一个重载运算符函数,将会导致编译器在直接使用该友元函数和对数值使用参数构造再对象相加中徘徊不定,这种情况下,两种重载+运算符的函数都适用于这种对象A和字符串相加的情况,编译器会报错。
2. 因为除了对象相加之外的情形都会使用到参数构造,所以要注意带参构造的具体实现要准确。
3.一般而言,只需要实现
Int(int var);
friend Int operator + (const int a, const Int& b);
Int operator + (const Int& b);
这三个函数就能很好的运作使用了。
可能有人会想,能不能不使用友元函数,答案是有些情形可以。
贴个代码:
#include <iostream>
using namespace std;
class Int {
public:
int num;
Int() {
num = 1;
cout << "默认构造" << endl;
}
Int(int var) {
#include <iostream>
using namespace std;
class Int {
public:
int num;
Int() {
num = 1;
cout << "默认构造" << endl;
}
Int(int var) {
num = var;
cout << "参数构造:" <<var<< endl;
}
// friend Int operator + (const int a, const Int& b);
Int operator + (const Int& b) {
cout << "对象相加:"<<b.num<<"+"<<num << endl;
return b.num + num;
}
Int operator + (const int b) {
cout << "单纯数字" << endl;
return num + b;
}
};
//Int operator + (const int a, const Int& b) {
// cout << "数值+对象" << endl;
// return b.num + a;
//}
int main()
{
Int var1, var2, var3, var4;
var1 = var2 + 9;//1
cout << endl;
var1 = 9 + var2;//2
cout << endl;
var1 = 9 + 8 + 7;//3
cout << endl;
var1 = var1 + var2 + var3;//4
cout << endl;
var1 = var1 + 8 + var2;//5
cout << endl;
var1 = 9 + var1 + 7;//6
cout << var1.num;
return 0;
}
在这种情况下,仅有被我贴上注释的2以及6的地方存在错误,错误是:
没有与这些操作数匹配的“+”运算符
操作数类型为int+Int
可以知道,这里存在一种需求,什么需求?顺序需求!
因此我们解除掉上面那条友元函数注释后,再编译一看,合格通过,运行成功。
所以,为了尽可能让重载的运算符符合各种情形,还是会需要用到友元函数来帮忙的。
如果有人运行了上面的代码,可能就会发现,在对象+数值的情形中,先把数值转成对象后再对象相加的情况,没了。取而代之的是,编译器使用到了我新写的一个函数:Int operator + (const int b)
我们对比一下:
通过对比,我们可以发现,使用:
Int(int var);
friend Int operator + (const int a, const Int& b);
Int operator + (const Int& b) ;
Int operator + (const int b);
这种方式的写法,虽然多了一个成员函数和在返回值那里会调用参数构造仍然是不可避免的,但他在达成同样的效果的前提下,有着更好的效率。
所以推荐使用最后这种写法。
本文是原创的分析文,我个人允许自由转载,如果上面的分析有缺漏错误之处,还请指出并讲述错误原因以及正确结论,本人一定会及时回复并更改,而不耽误后来人,谢谢观看。