一、 运算符重载
1. 什么是运算符重载
重载这个概念在早前的函数重载,大家已经见识过了。函数可以重载, 运算符也是可以重载。 运算符重载就是对已有的运算符重新进行定义,赋予其另一种功能,以达到适应不同的数据类型。运算符重载不能改变它本来的寓意(也就是 加法不能变更为 减法)
运算符重载只是一种 “语法上的方便” , 它只是一种函数调用的方式。
int a = 3 ;
int b = 4 ;
int c = a + b ; //编译器通过
Student s1 ;
Student s2 ;
Student s3 = s1 + s2 ; // 编译器不通过
2. 定义运算符重载
重载的运算符是带有特殊名称的函数,函数名是由关键字
operator
和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。假如我们需要把两个学生的年纪 和 体重 各自相加,然后得出第三个学生的数值。那么使用运算符重载可以如此编写:
- 以前写法
class Student{
public:
int age ;
int weight;
public :
Student(age_val , weight_val):age{age_val},weight{weight_val}{
}
};
Student s1(18 , 120);
Student s2(20 , 90);
int age = s1.age + s2.age ;
int weight = s1.weight + s2.weight ;
Student s3 (age , weight);
- 运算符重载
运算符可以写成全局函数也可以写成成员函数。
- 全局函数
Student operator+ (Student &s1 , Student &s2){
Student temp(s1.age + s2.age , s1.weight + s2.weight);
return temp;
}
- 成员函数
Student operator+ ( Student &s2){
Student temp(this.age + s2.age , this.weight + s2.weight);
return temp;
}
3. 运算符重载练习
1. 输出运算符重载
其实这里说就是我们平常见过的
<<
。<<
实际上是位移运算符,但是在c++里面,可以使用它来配合cout
进行做控制台打印输出。cout
其实是ostream
的一个实例,而ostrem
是 类basic_ostream
的一个别名,所以之所以能使用cout <<
来输出内容,全是因为basic_ostream
里面对<<
运算符进行了重载.
#include <iostream> //由于这里引入了iostream 所以下面可以直接对 << 进行重载
class Student{
public:
string name {"zhangsan"};
public:
Student(string name){
this->name = name;
}
};
//对 << 运算符进行重载。
ostream& operator<< (ostream& o, Student &s1){
o << s1.name ;
return o;
}
int main() {
Student s1("张三");
cout << s1 <<"i" ;
return 0;
}
2. 输入运算符重载
#include <iostream> //由于这里引入了iostream 所以下面可以直接对 << 进行重载
//对 << 运算符进行重载。
ostream& operator<< (ostream& o, Student &s1){
o << s1.name ;
return o;
}
//对 >> 运算符进行重载
istream& operator>> (istream& in, Student &s1){
in >> s1.name;
return in;
}
int main() {
Student s1("张三");
cout << s1 <<"i" ;
return 0;
}
4.赋值运算符重载
- 默认的赋值运算符
赋值运算符在此前编码就见过了,其实就是
=
操作符 。
stu s1;
stu s2;
s2= s1; //拷贝赋值
s2 = move(s1); // 一旦有这行代码,表示s1不能用了。
class Student{
int no;
int age ;
public :
Student(no , age){
this->no = no ;
this->age = age ;
}
}
Student s1(10001 , 15);
Student s2 ;
s2 = s1; //此处使用了默认的赋值运算符。
Student s2 = s1;
1. 拷贝赋值运算
其实这里说的就是
=
赋值运算符
//拷贝赋值
Stu& operator=(const Stu &h){
cout <<"执行拷贝赋值函数" << endl;
d = new int();
*d = *h.d;
}
- main
int main(){
Stu stu1("张三",18);
Stu stu2 ;
stu2 = stu1; //拷贝赋值
}
2. 移动赋值运算
移动赋值运算,接收的是一个右值,并且移动之后,原有对象将不再拥有对数据的控制权。
//移动赋值
Stu& operator=(const Stu &&h){
cout <<"执行移动赋值函数" << endl;
d = h.d;
h.d = nullptr;
return *this;
}
- main
int main(){
Stu stu1("张三",18);
Stu stu2 ;
stu2 = move(stu1); //移动后,stu1 将不再拥有对数据的控制权
}
5. 调用运算符重载
一般来说,可以使用对象来访问类中的成员函数,而对象本身是不能像函数一样被调用的,除非在类中重载了
调用运算符
。 如果类重载了函数调用运算符,则我们可以像使用函数一样使用该类的对象。在外面使用对象()
,实际上背后访问的是类中重载的调用运算符函数。如果某个类重载了调用运算符,那么该类的对象即可称之为:函数对象 ,因为可以调用这种对象,所以才说这些对象行为
像函数一样
。
class Calc{
public:
int operator()(int val){
return val <0 ? -val :val;
}
};
int main(){
Calc c ;
int value = c(-10);
return 0;
}
- 标准库中定义的函数对象
在标准库中定义了一组算术运算符 、关系运算符、逻辑运算符的类,每个类都有自己重载的调用运算符。要想使用这些类,需要导入
#include<functional>
, 后面要说的lamdda表达式
正是一个函数对象
plus<int > p; //加法操作
int a = p(3 , 5);
negate<int> n; //可以区绝对值
cout <<n(-10) << endl;