目录
一. 前言
C++运算符的重载总共可以分为六种,分别为加号运算符重载,左移运算符重载,递增运算符重载,赋值运算符重载,关系运算符重载,函数调用运算符重载。下面我来分别介绍这六种运算符重载的方法和实现。
所谓运算符重载,也就是堆已有的运算符重新进行定义,赋予另一种功能,以适应不同的数据类型。
二. 加号运算符重载
我们大家都知道普通的加法运算,例如我们从小就学习的1+1,是等于2的。这里我们的程序也能计算出来,但如果进行加法运算的两个对象不是两个整形数据,而是由自己定义的数据类型呢?这个时候编译器就无法得出计算结果,由此也就引出我们加号运算符的重载。
话不多说,我们直接来看进行了加号运算符重载的源代码:
#include<iostream>
using namespace std;
//实现加号运算符的重载
class Person {
public:
Person(int num) {
m_num = num;
}
Person& operator+(Person p1) {
Person temp(0);
temp.m_num = this->m_num + p1.m_num;
return temp;
}
int m_num;
};
void test01() {
Person p1(10);
Person p2(20);
Person p3 = p1.operator+(p2);
cout << "p1= " << p1.m_num << endl;
cout << "p2= " << p2.m_num << endl;
cout << "p3= " << p3.m_num << endl;
}
int main() {
test01();
return 0;
}
如上代码所示,我们在Person类当中重载了运算符+号,使它能够实现两个我们自己定义的数据类型相加。最后值得注意的是,代码Person p3=p1.operator+(p2)其实就等价于p3=p1+p2;
三. 左移运算符重载
举个例子,由于左移运算符的输出结构类似于cout<<p<<endl; 这个时候,我们的cout就位于了<<的左侧,所以我们无法利用成员函数重载<<运算符,因为无法实现cout在左侧。
这个时候就只能利用全局函数重载。
在这里给大家拓展一个知识点,如果不了解某个专业术语或者名称的数据类型或结构,就可以点击鼠标右键,然后再次点击跳转到定义处,就能查询了。例如在此之前大家并不了解cout的数据类型,而我们在经过查询后就可以得出,cout为ostream数据类型。
下面我们来看下实现左移运算符重载的源代码:
#include<iostream>
using namespace std;
//实现左移运算符<<的函数重载
class Person {
public:
int m_A;
int m_B;
Person() {
m_A = 10;
m_B = 23;
}
};
ostream& operator<<(ostream &cout,Person &p) {
cout<<"p.m_A= " << p.m_A << endl;
cout<<"p.m_B= " << p.m_B << endl;
return cout;
}
void test01() {
Person p1;
cout << p1 << endl;
}
int main() {
test01();
return 0;
}
在对<<重载的函数中,为了能使cout<<p1后面能再接上请按任意键继续的界面,所以需要返回一个cout,而cout的数据类型为ostream,并且是引用类型的。
四. 递增运算符重载
为了区分前置递增和后置递增,我们规定void operator++(int)为后置++运算符,其中的int代表占位参数。
#include<iostream>
using namespace std;
class MyInter{
public:
MyInter(){
m_age=0;
}
MyInter& operator++(){
m_age++;
return *this;
}
int operator++(int){
int temp;
temp=*this;
m_age++;
return temp;
}
int m_age;
}
void test01(){
MyInter myinter;
cout<<++myinter<<endl;
cout<<myinter<<endl;
}
void test02(){
MyInter myinter;
cout<<myinter++<<endl;
cout<<myinter<<endl;
}
int main(){
test01();
test02();
return 0;
}
如上述代码所示,test01测试函数测试了前置递增的结果,test02测试函数测试了后置递增的结果。值得注意的是后置递增的重载,返回值跟前置递增重载的返回值有很大区别。
五. 赋值运算符重载
在赋值运算符中,如果不实现深拷贝,程序就会因为浅拷贝所带来的问题而导致整个程序崩溃。实现过程可概括为:先判断原来的堆区是否已经被释放,如果没有,则重新进行释放,然后再开辟一个新的空间。并且为了能进行连续赋值操作,我们需要在重载函数中返回这个本身,也就是*this
#include<iostream>
using namespace std;
//进行赋值运算符的重载
class Person {
public:
Person(int age) {
m_age = new int(age);
}
~Person() {
if (m_age != NULL) {
delete m_age;
m_age = NULL;
}
}
Person& operator=(Person& p) {
if (m_age != NULL) {
delete m_age;
m_age = NULL;
}
m_age = new int(*p.m_age);
return *this;
}
int *m_age;
};
void test01() {
Person p1(19);
Person p2(20);
p1 = p2;
cout << "p1的年龄为:" << *p1.m_age << endl;
cout << "p2的年龄为:" << *p2.m_age << endl;
}
int main() {
test01();
return 0;
}
六. 关系运算符重载
值得注意的是,关系运算符重载函数的返回值为bool类型,因为返回的是true和false。
#include<iostream>
using namespace std;
class MyInter{
public:
int m_a;
int m_b;
MyInter(int a,int b){
m_a=a;
m_b=b;
}
bool operator!=(MyInter myinter){
if(m_a!=myinter.m_a&&m_b!=myinter.m_b){
return true;
}
else{
return false;
}
}
void test01(){
MyInter my1(10,20);
MyInter my2(10,20);
if(my1!=my2){
cout<<"my1和my2是不相等的"<<endl;
}
else{
cout<<"my1和my2是相等的"<<endl;
}
}
int main()
{
test01();
return 0;
}
如上代码所示,我们进行关系运算符中不等于的重载,由于我们所定义的my1和my2里面的两个数据都是相同的,因此最后的输出结果也是两者相同的结果。
七. 函数调用运算符重载
在学习了上面五种运算符的重载之后,没想到我们的函数调用也是可以重载的吧。由于重载后的函数调用使用方式非常像函数的调用,因此我们也称为仿函数。仿函数没有固定写法,非常灵活。
拓展小知识:如果在这个过程中,我们不想要创建一个对象,那么就可以使用一个匿名对象来调用。
#include<iostream>
using namespace std;
class MyAdd {
public:
int operator()(int v1,int v2){
return v1 + v2;
}
};
void test01() {
MyAdd add;
int ret=add(3, 4);
cout << "ret= " << ret << endl;
cout << "MyAdd()(100,100)= " << MyAdd()(100, 100) << endl;
}
int main() {
test01();
return 0;
}
如上述代码所示中,MyAdd()就是一个匿名函数的调用。