运算符重载(全局函数)
- 比如说对于小于号和大于号,如果说是内置类型的话,可以直接进行比较,因为内置类型是祖师爷定义的,那祖师爷肯定知道比方说int类型怎么比,double类型怎么比,因为他肯定知道内置类型是怎么去进行比较,肯定就把相关的规则给他融合到指令当中,他是明牌。
- 但是如果说自定义类型的话,因为自定义类型是我们自己定义的,所以说可以五花八门,所以说祖师爷他不知道我们自己定义的各种各样的自定义类型之间该怎么去比较,所以说对于自定义类型而言,不能直接用小于号,大于号去进行比较。
- 因为自定义类型是我们自己定义的,***所以说对于自定义类型之间的比较的话,我们自己是知道的,***所以如果说我需要用小于号去比较一下两个自定义类型变量的话,那么我就需要把小于号这个运算符给他重载一下。
- 编译器如果碰到内置类型比较大小的话,因为他是知道内置类型是怎么去比较的,所以说就会直接转化为指令。然后对于自定义类型的话,它会转化为去调用这个函数operator>(打个比方)
- 运算符重载在实际上就是相当于我们希望对于自定义类型变量也可以像内置类型那样去使用运算符,因为这样子可读性就会更高
- 实际上在特定的场景下面,并不是所有的运算符都有意义,是否要重载运算符,取决于这个运算符对于这个类是否有意义。
- 然后由于自定义类型已经是相对来说一个比较复杂的类型了。要用运算符来进行比较的话,也不是很容易。所以这时候我们就自己去写一个函数来进行自我实现。也就是自己去修改这个运算符的实现逻辑(如果说这个运算符它的操作数是一个内置类型,那么就会直接转化为指令,如果说不是内置类型,那么就直接会去调用你自己写的这个运算符重载函数,所以说本质上就是转化成一个函数)
- 然后再实现这个运算符重载函数的时候,由于肯定会涉及到自定义类型实例化对象的传参,这时候结合之前的知识会发现肯定需要用引用与const为佳。
- 在运算符重载的时候不能够去创造新的符号
- 对于那些乱七八糟的符号,就是不是运算符的符号是不能够进行运算符重载,然后有些符号它即使是作为运算符,但是也不能进行运算符重载,有5个:.* sizeof : : ?: .
- 代码样本:
#include <iostream>
#include <stdlib.h>
#include <stdbool.h>
using namespace std;
class Stu
{
public:
//成员变量
char* name;
int age;
double score;
//成员函数
//构造函数
Stu(int size = 10)
{
name = (char*)malloc(sizeof(char) * size);
if (name == nullptr)
{
perror("malloc failed");
return;
}
age = 0;
score = 0;
}
void input()
{
cout << "依次输入姓名,年龄与成绩:";
cin >> name >> age >> score;
}
void output()
{
cout << name << " " << age << " " << score << endl;
}
~Stu()
{
free(name);
}
};
void operator>(const Stu& x1, const Stu& x2) //比较年龄
{
if (x1.age > x2.age)
{
cout << "是的,"<< x1.name << "的年龄更大,为" << x1.age << "岁!" << endl;
}
else if (x1.age < x2.age)
{
cout << "不对" << x2.name << "的年龄更大,为" << x2.age << "岁!" << endl;
}
else
{
cout << "不完全对,两者年龄一样大" << endl;
}
}
void operator<(const Stu& x1, const Stu& x2) //比较年龄
{
if (x1.score < x2.score)
{
cout << "是的," << x1.name << "的成绩更低,为" << x1.score << "分!" << endl;
}
else if (x1.score > x2.score)
{
cout << "不是," << x2.name << "的成绩更低,为" << x2.score << "分!" << endl;
}
else
{
cout << "不完全对,两者成绩一样" << endl;
}
}
int main()
{
Stu s1;
Stu s2;
s1.input();
s2.input();
cout << "s1>s2(我在比较年龄):";
s1 > s2;
cout << "s1<s2(我在比较成绩):";
s1 < s2;
return 0;
}
以后对于例化对象进行函数的传值调用,用于函数的传值返回,最好都去使用一下引用,并且如果可以的话,最好都加上const
运算符重载(类的成员函数)
-
但是到目前为止还存在着一个问题,由于在类的外面的话,不能够去访问那些私有或者受保护的成员变量,那如果说两个类的实例化对象需要去进行用运算符去比较的话,那么在那个具体实现逻辑的函数里面,必须需要去访问那些类的成员变量,需要与它打交道。那虽然在类外面无法进行访问,但是在类的里面的话是没有任何限制的,那就可以把那个运算符重载的函数给它放到类的里面去充当一个成员函数不就OK?但如果单独去这么做的话,你会发现还是编不过去
-
你想按道理来讲的话,如果说这个操作符它所能连接到的操作数有几个,那么在这个运算符重载函数当中的参数就应该有几个,比如说对于运算符重载函数operator>,那么这个函数它的参数肯定是两个。如果把运算符操作函数给它充当类的成员函数里面,这边就需要注意一个大坑,因为类的成员函数都隐藏着第一个参数,也就是this指针(类型* const this),这个隐藏的参数this指针其实就可以取代其中的某一个参数去进行对于某个实例化对象的成员访问
-
this指针真想揭露:
-
自定义类型的运算符重载在本质上就是在调用函数,但无非就是作为成员函数的时候,看起来参数好像少了一个的样子
-
代码样本:
#include <iostream>
#include <stdlib.h>
#include <stdbool.h>
using namespace std;
class Stu
{
public:
//成员函数
//构造函数
Stu(int size = 10)
{
name = (char*)malloc(sizeof(char) * size);
if (name == nullptr)
{
perror("malloc failed");
return;
}
age = 0;
score = 0;
}
void input()
{
cout << "依次输入姓名,年龄与成绩:";
cin >> name >> age >> score;
}
void output()
{
cout << name << " " << age << " " << score << endl;
}
void operator>(const Stu& x2) //比较年龄
{
if (age > x2.age)
{
cout << "是的," << name << "的年龄更大,为" << age << "岁!" << endl;
}
else if (age < x2.age)
{
cout << "不对" << x2.name << "的年龄更大,为" << x2.age << "岁!" << endl;
}
else
{
cout << "不完全对,两者年龄一样大" << endl;
}
}
void operator<(const Stu& x2) //比较年龄
{
if (score < x2.score)
{
cout << "是的," << name << "的成绩更低,为" << score << "分!" << endl;
}
else if (score > x2.score)
{
cout << "不是," << x2.name << "的成绩更低,为" << x2.score << "分!" << endl;
}
else
{
cout << "不完全对,两者成绩一样" << endl;
}
}
~Stu()
{
free(name);
}
private:
char* name;
int age;
double score;
};
int main()
{
Stu s1;
Stu s2;
s1.input();
s2.input();
cout << "s1>s2(我在比较年龄):";
s1 > s2;
cout << "s1<s2(我在比较成绩):";
s1 < s2;
return 0;
}
- 然后对于普通的运算符重载函数的话,他就可以写在类的外面,也就是可以写在全局域当中,但往往运算符重载函数会涉及到需要访问某个类的实例化对象的成员变量,而在全局那边有可能会受到访问限制符的限制,所以说针对特定类的某些运算符重载函数也一般是写在类的成员函数当中,这样在类里面的话就不会受到访问限定符的限制
补充与总结
- 对于那些比较运算符进行重载的时候,运算符之间本身就有一种互斥的关系,所以说这边就可以进行一些复用
- 于此同时在运算符重载的过程当中并没有规定操作数必须都是同一个类型,而仅仅只是规定了在操作数当中必须至少有一个是自定义类型,就是说不能全部都是内置类型,因为假设全部都是内置类型的话,那么就可以直接转化为指令了
- 总结图: