一、运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
1.1 加号运算符重载
作用:实现两个自定义数据类型相加的运算
#include <iostream>using namespace std;class Person
{
public:// 1. 成员函数重载+号/*Person operator+(Person& p){Person temp;temp.m_a = this->m_a + p.m_a;temp.m_b = this->m_b + p.m_b;return temp;}*/int m_a;int m_b;
};// 2. 全局函数重载+号
Person operator+(Person& p1, Person& p2)
{Person temp;temp.m_a = p1.m_a + p2.m_a;temp.m_b = p1.m_b + p2.m_b;return temp;
}// 运算符重载也可以发生函数重载
Person operator+(Person& p1, int num)
{Person temp;temp.m_a = p1.m_a + num;temp.m_b = p1.m_b + num;return temp;
}void test()
{Person p1;p1.m_a = 10;p1.m_b = 20;Person p2;p2.m_a = 5;p2.m_b = 1;// 成员函数重载Person p3;// p3 = p1.operater+(p2);p3 = p1 + p2;cout << "p3.m_a = " << p3.m_a << endl;cout << "p3.m_b = " << p3.m_b << endl;// 全局函数重载Person p4;// p3 = operator+(p1,p2);p4 = p1 + p2;cout << "p4.m_a = " << p4.m_a << endl;cout << "p4.m_b = " << p4.m_b << endl;// 运算符重载也可以发生函数重载Person p5;p5 = p1 + 100;cout << "p5.m_a = " << p5.m_a << endl;cout << "p5.m_b = " << p5.m_b << endl;
}int main(int argc, char* argv[])
{test();return 0;
}
总结1:对于内置的数据类型的表达式的运算符是不可能改变的
总结2:不要滥用运算符重载
1.2 左移运算符重载
作用:可以输出自定义数据类型
#include <iostream>using namespace std;class Person
{friend ostream& operator<<(ostream& cout, Person& p);// 利用成员函数重载左移运算符 p.operator<<(p1) === p << p1// p.operator<<(cout) === p << cout// 综上所述一般不会利用成员函数重载<<运算符,因为无法实现cout在左侧
public:void setA(int a){m_a = a;}void setB(int b){m_b = b;}
private:int m_a;int m_b;
};ostream& operator<<(ostream& cout, Person& p)
{cout << "m_a = " << p.m_a << endl;cout << "m_b = " << p.m_b;return cout;
}int main(int argc,char* argv[])
{Person p;p.setA(10);p.setB(13);cout << p << endl;return 0;
}
总结:重载左移运算符配合友元可以实现输出自定义数据类型
1.3 递增运算符重载
作用:通过重载递增运算符,实现自己的整型数据
#include <iostream>using namespace std;class MyInteger
{friend ostream& operator<<(ostream& cout, MyInteger myint);
public:MyInteger(){m_num = 0;}// 重置前置++运算符 返回应用是为了一直对一个数据进行递增操作MyInteger& operator++(){// 先++m_num++;// 再返回return *this;}// 重置后置++运算符 int代表占位参数,可以用于区分前置和后置递增MyInteger operator++(int){// 先返回数据,再递增// 如果先return返回后续递增不执行// 转变成先记录数据,再递增,最后返回记录的数据MyInteger temp = *this;m_num++;return temp;}private:int m_num;
};// 重载 << 运算符
ostream& operator<<(ostream& cout, MyInteger myint)
{cout << myint.m_num;return cout;
}void test01()
{MyInteger myint;cout << ++(++myint) << endl;cout << myint << endl;
}void test02()
{MyInteger myint;cout << (myint++)++ << endl;cout << myint << endl;
}int main(int argc, char* argv[])
{test01();test02();return 0;
}
总结:前置递增返回的是引用,后置递增返回的是值
1.4 赋值运算符重载
C++编译器至少给一个类添加4个函数
1. 默认构造函数(无参,函数体为空)
2. 默认析构函数(无参,函数体为空)
3. 默认拷贝构造函数,对属性进行值拷贝
4. 赋值运算符 operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
#include <iostream>using namespace std;class Person
{
public:Person(int age){m_age = new int(age);}int* m_age;~Person(){if (m_age != NULL){delete m_age;m_age = NULL;}}// 利用深拷贝解决浅拷贝带来的问题Person& operator=(Person& p){// 编译器提供的是浅拷贝// m_age = p.m_age;// 应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝if (m_age != NULL){delete m_age;m_age = NULL;}// 深拷贝m_age = new int(*p.m_age);return *this;}
};void test01()
{Person p1(18);cout << "p1的年龄为:" << *p1.m_age << endl;Person p2(23);cout << "p2的年龄为:" << *p2.m_age << endl;Person p3(30);cout << "p2的年龄为:" << *p2.m_age << endl;// 浅拷贝会导致堆区内存重复释放// 赋值运算符重载p3 = p2 = p1;cout << "p2的年龄为:" << *p2.m_age << endl;cout << "p2的年龄为:" << *p2.m_age << endl;cout << "p2的年龄为:" << *p2.m_age << endl;
}int main(int argc, char* argv[])
{test01();return 0;
}
1.5 关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
#include <iostream>
#include <string>using namespace std;class Person
{
public:Person(string name, int age){m_Name = name;m_Age = age;}bool operator==(Person& p){if (this->m_Age = p.m_Age && this->m_Name == p.m_Name){return true;}return false;}string m_Name;int m_Age;
};void test01()
{Person p1("张三", 18);Person p2("李四", 23);Person p3("李四", 23);if (p1 == p2){cout << "p1等于p2" << endl;}else{cout << "p1不等于p2" << endl;}if (p2 == p3){cout << "p2等于p3" << endl;}else{cout << "p2不等于p3" << endl;}
}int main(int argc, char* argv[])
{test01();return 0;
}
1.6 函数调用运算符重载
函数调用运算符 () 也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活
#include <iostream>
#include <string>using namespace std;class MyPrint01
{
public:// 重载函数调用运算符void operator()(string text){cout << text << endl;}
};void MyPrint02(string text)
{cout << text << endl;
}class MyAdd01
{
public:// 重载函数调用运算符double operator()(double a, double b){return a + b;}
};double MyAdd02(double a, double b)
{return a + b;
}void test01()
{MyPrint01 MyPrint01;MyPrint01("hello world");MyPrint02("hello world");MyAdd01 myAdd01;double result01 = myAdd01(10, 20);double result02 = MyAdd02(10, 20);cout << "myAdd01仿函数计算的结果为:" << result01 << endl;cout << "MyAdd02函数计算的结果为:" << result02 << endl;// 匿名函数对象 类名+()为匿名对象,后面的重载的运算符cout << "匿名函数对象的计算结果为:" << MyAdd01()(10, 20) << endl;
}int main(int argc, char* argv[])
{test01();return 0;
}