1 概念
C++中可以把部分算符看做成函数,此时运算符也可以重载。
运算符预定义的操作只支持基本数据类型,但是对于自定义类型,也需要类似的运算符操做,此时就可以重新定义这些运算符的功能,使其支持特定类型,完成特定操作。
运算符重载有两种实现方式:
- 友元函数运算符重载
- 成员函数运算符重载
2 友元函数运算符重载
#include <iostream>
using namespace std;
class Myint
{
private:
int a;
public:
Myint(int a)
{
this->a=a;
}
int get_int()
{
return a;
}
//+ 运算符重载声明
friend Myint operator +(Myint &i,Myint &i2);
};
Myint operator +(Myint &i,Myint &i2)
{
//触发隐式调用构造函数 int -> Myint
// Myint myint(0);
// myint.a=i.a+i2.a;
//return myint.a;
return i.a+i2.a;
}
int main()
{
Myint int1(2);//构造对象int1并赋值成员变量a为2
Myint int2(int1); // 拷贝构造函数 对象int2 int2.a=2
Myint int3 = int1 + int2;//对象int1+对象int2,内部成员变量
cout << int3.get_int() << endl;
int x=1+2;//运算符 原功能不变
cout << x<< endl;
return 0;
}
自增运算符重载
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
public:
MyInt(int a)
{
this->a = a;
}
int get_int()
{
return a;
}
//+ 运算符重载
friend MyInt operator +(MyInt &i,MyInt &i2);
friend MyInt operator ++(MyInt &i); // 前置++
friend MyInt operator ++(MyInt &i,int); // 后置++,通过哑元区分前后自增(哑元必须是int类型)
};
MyInt operator +(MyInt &i,MyInt &i2)
{
// 触发隐式调用构造函数 int ->MyInt
// MyInt myint(0);
// myint.a = i.a + i2.a;
return i.a + i2.a;
}
MyInt operator ++(MyInt &i)
{
return ++i.a;
}
MyInt operator ++(MyInt &i,int)
{
return i.a++;
}
int main()
{
MyInt int1(2);
MyInt int2(int1); // 拷贝构造函数
MyInt int3 = int1 + int2;
cout << int3.get_int() << endl;
cout << (++int3).get_int() << endl;
cout << (int3++).get_int() << endl;//后置++自动寻找后置++重载,不用传值
cout << (int3++).get_int() << endl;
return 0;
}
3 成员函数运算符重载-友元函数的第一个传入的参数,在成员函数中用this指针替代
成员函数运算符重载相比较于友元函数运算符重载,最大的区别在于,友元函数的第一个传入的参数,在成员函数中用this指针替代。因此成员函数运算符重载,相比较与友元函数运算符重载,参数少一个。
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
public:
MyInt(int a)
{
this->a = a;
}
int get_int()
{
return a;
}
//+ 运算符重载
MyInt operator +(MyInt &i2);
MyInt operator ++(); // 前置++
MyInt operator ++(int); // 后置++
};
MyInt MyInt::operator +(MyInt &i2)
{
return this->a + i2.a;
}
MyInt MyInt::operator ++()
{
return ++this->a;
}
MyInt MyInt::operator ++(int)
{
return this->a++;
}
int main()
{
MyInt int1(2);
MyInt int2(int1); // 拷贝构造函数
MyInt int3 = int1 + int2;
cout << int3.get_int() << endl;
cout << (++int3).get_int() << endl;
cout << (int3++).get_int() << endl;
cout << (int3++).get_int() << endl;
return 0;
}
4 其他运算符重载
部分运算符重载不支持友元函数运算符重载,只支持成员函数运算符重载。比如说(类型转换运算符重载,必须使用成员函数运算符重载)。
4.1 赋值运算符重载‘=’
如果程序员不手动编写赋值运算符重载,则赋值运算符重载会被编译器自动添加。
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
public:
MyInt(int a)
{
this->a = a;
}
int get_int()
{
return a;
}
// 编译器自动添加的赋值运算符重载函数
MyInt & operator =(MyInt &i)
{
cout << "我自己添加的赋值运算符重载" << endl;
//若成员变量包含指针,则赋值运算符重载需要自己new开辟空间,解决浅拷贝的局限性
this->a = i.a;
return *this;
}
};
int main()
{
MyInt int1(2);
MyInt int2(int1); // 拷贝构造函数
MyInt int3(3);
int3 = int2; // 赋值运算符重载
cout << int3.get_int() << endl;
return 0;
}
当类中出现指针类型的成员变量时,默认的赋值运算符重载函数类似于默认的浅拷贝构造函数,因此也需要手动编写解决浅拷贝的问题。
4.2 类型转换运算符重载
必须使用成员函数运算符重载,且格式比较特殊。
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
string str = "hello";
public:
MyInt(int a)
{
this->a = a;
}
int get_int()
{
return a;
}
// 类型转换运算符重载
operator int()
{
return a;
}
operator string()
{
return str;
}
};
int main()
{
MyInt int1(2);
int a = int1;//目的,直接用类赋值
cout << a << endl;
return 0;
}
5 注意事项
- 重载的运算符限制再C++语言中已有的运算符范围,不能创建新的运算符。
- 运算符重载本质上也是函数重载,但是不支持函数默认值设定。
- 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。
- 运算符重载必须基于或包含自定义类型,即不能改变基本数据类型的运算规则。
- 重载的功能应该与原有的功能相似,避免没有目的滥用运算符重载。
- 一般情况下,双目运算符建议使用友元函数进行重载,单目运算符建议使用成员函数。
6 函数参数默认值
- 默认值参数是指给函数赋予一个值,调用时如果没有参数传入,就会使用默认值参数。
- 默认参数使用时需要注意,从被赋予默认参数的参数开始,后面的参数都要赋予默认参数。