目录
一、运算符重载
二、加号运算符重载
三、左移运算符重载
将类中的成员设置为私有属性,将全局函数设置为友元访问类中的成员
四、递增运算符
五、赋值运算符重载
六、关系运算符重载
七、函数调用运算符重载
一、运算符重载
对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型
二、加号运算符重载
作用:实现两个自定义数据相加的运算
是自定义的一个函数作用,函数的名称替换成编译器统一提供的名字
运算符重载也可以发生函数重载
函数名 替换成 : operator+
总结注意:
- 对于内置的数据类型的表达式的运算符是不可能改变的
- 不可以滥用运算符重载
示例:
#include<iostream>
using namespace std;
// 加号运算符重载
class person {
public:
// 1.成员函数重载
person operator+(person& p)
{
person temp;
temp.A = this->A + p.A;
temp.B = this->B + p.B;
return temp;
}
int A;
int B;
};
// 2.全局函数重载+号
person operator+(person& p1, person& p2)
{
// 全局函数的本质调用是:
// person p3 = operator+(p1,p2);
person temp1;
temp1.A = p1.A + p2.A;
temp1.B = p1.B + p2.B;
return temp1;
}
// 运算符重载也可以发生函数重载
person operator+(person& p1, int num)
{
person temp1;
temp1.A = p1.A + num;
temp1.B = p1.B + num;
return temp1;
}
void test01()
{
person p1;
p1.A = 10;
p1.B = 10;
person p2;
p2.A = 10;
p2.B = 10;
// 成员函数的本质调用是
person p3 = p1.operator+(p2);
cout << "成员函数的运算符重载调用后:" << endl << "p3.A:" << p3.A << "\tp3.B:" << p3.B << endl;
// 全局函数重载的本质调用
person p4 = operator+(p1,p2);
cout << "全局函数的运算符重载调用后:" << endl << "p4.A:" << p4.A << "\tp4.B:" << p4.B << endl;
// 成员函数与全局函数都可以用以下方式直接相加
//person p6 = p1 + p2;
//cout << "p3的A的值:" << p3.A << endl << "p3的B的值:" << p3.B << endl;
//函数重载
person p5 = p1 + 5;
cout << "函数重载完后p5的A的值:" << p5.A << endl << "p5的B的值:" << p5.B << endl;
}
int main()
{
test01();
return 0;
}
运行结果:
三、左移运算符重载
作用:可以实现输出自定义类型
总结:重载左移运算符配合友元可以实现输出自定义数据类型。
示例:
#include<iostream>
using namespace std;
// 左移运算符重载
class person {
public:
// 1.成员函数重载左移运算符
// 利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本是: p<<cout
// 一般不利用成员函数重载左移运算符,因为无法实现cout在左侧
// 实现的方式是p << cout
int A;
int B;
};
// 2.全局函数重载左移运算符
ostream& operator<<(ostream& cout, person& p)
{
// ostream 是输出流
cout << "A = " << p.A << endl << "B = " << p.B << endl;
return cout;// 返回的还是输出流对象,为了能够链式编程
}
// cout重载完再返回cout,在重载调用完后还可以继续输出
// return cout 或者 out 都是可以的, 用引用的方式调用,out本质上是cout的一个别名
void test01()
{
person p1;
p1.A = 10;
p1.B = 10;
cout << p1 << "Hello World!" << endl;
}
int main()
{
test01();
return 0;
}
运行结果:
将类中的成员设置为私有属性,将全局函数设置为友元访问类中的成员
示例:
#include<iostream>
using namespace std;
// 左移运算符重载
class person {
friend ostream& operator<<(ostream& cout, person& p);
public:
person(int a,int b)
{
this->A = a;
this->B = b;
}
private:
// 1.成员函数重载左移运算符
// 利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本是: p<<cout
// 一般不利用成员函数重载左移运算符,因为无法实现cout在左侧
// 实现的方式是p << cout
int A;
int B;
};
// 2.全局函数重载左移运算符
ostream& operator<<(ostream& cout, person& p)
{
// ostream 是输出流
cout << "A = " << p.A << endl << "B = " << p.B << endl;
return cout;// 返回的还是输出流对象,为了能够链式编程
}
// cout重载完再返回cout,在重载调用完后还可以继续输出
// return cout 或者 out 都是可以的, 用引用的方式调用,out本质上是cout的一个别名
void test01()
{
person p1(100,100);
cout << p1 << "Hello World!" << endl;
}
int main()
{
test01();
return 0;
}
运行结果:
四、递增运算符
前置递增返回引用,后置递增返回值
示例:
#include<iostream>
#include<math.h>
using namespace std;
// 重载递增运算符
// 自定义整形
class my_Integer {
friend ostream& operator<< (ostream& cout, my_Integer myint);
public:
my_Integer()
{
my_num = 0;
}
// 重置前置++运算符
my_Integer& operator++()
{
my_num++; // 进行++
return *this; // 返回自身
// 返回引用是为了一直对一个数进行操作
}
// 重置后置++运算符
// 后置++不能返回引用是因为不能返回局部变量
my_Integer operator++(int) // int 代表是占位参数 可以用于区分 前置和后置递增
{
// 先记录
my_Integer temp = *this;
// 后递增
my_num++;
// 最后将记录的结果返回
return temp;
}
private:
int my_num;
};
// 重载左移运算符
ostream& operator<< (ostream& cout, my_Integer myint)
{
cout << myint.my_num;
return cout;
}
// 前置++
void test01()
{
my_Integer myint;
cout << "myint1,前置++" << endl << "++(++myprint) = " << ++(++myint) << " myprint = " << myint << endl;
}
// 后置++
void test02()
{
my_Integer myint2;
cout << "myint2,后置++" << endl << "(myprint2++) = " << myint2++ << " myprint2 = " << myint2 << endl;
}
int main()
{
int a = 10;
cout << "后置++,先输出数据,再++" << endl;
cout << a++ << endl;
cout << a << endl;
int b = 10;
cout << "前置++,输出++结果" << endl;
cout << ++b << endl;
cout << b << endl;
test01();
test02();
return 0;
}
运行结果:
五、赋值运算符重载
C++编译器至少给一个类添加4个函数:
- 默认构造函数 (无参,函数体为空)
- 默认析构函数 (无参,函数体为空)
- 默认拷贝构造函数 (对属性进行拷贝)
- 赋值运算符 operator=, 对属性进行值拷贝(浅拷贝)
作用:如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。
示例:
#include<iostream>
#include<math.h>
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)// 链式编程的思想,需要返回本身
{
// 编译器提供的是两个指针指向同一个地址,在堆区的内容释放的时候只能释放一次,而引起的深,浅拷贝的问题
// m_age = p.m_age;
// 编译器提供的是浅拷贝,导致拷贝得到的是堆区地址,堆区的空间只能释放一次,而浅拷贝导致释放两次
// 应该先判断是否有属性在堆区,如果有先释放然后深拷贝
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 p(18) ;
cout<<"p的年龄:"<<*p.m_age<<endl;
person p1(20);
cout<<"p1的年龄:"<<*p1.m_age<<endl;
person p2(10);
cout<<"p2的年龄:"<<*p2.m_age<<endl;
cout<<"-------------------------------"<<endl;
cout<<"重载完=后:"<<endl;
p2=p1=p; // 返回的是自身,可以连等
cout<<"p的年龄:"<<*p.m_age<<endl;
cout<<"p1的年龄:"<<*p1.m_age<<endl;
cout<<"p2的年龄:"<<*p2.m_age<<endl;
}
int main()
{
test01();
return 0;
}
运行结果:
六、关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
示例:
#include<iostream>
#include<math.h>
using namespace std;
// 重载关系运算符
class person {
public:
person(string name, int age)
{
this->name = name;
this->age = age;
}
// 重载==号
bool operator==(person& p)
{
if (this->name == p.name && this->age == p.age)
{
return true;
}
return false;
}
// 重载不等号
bool operator!=(person &p)
{
if(this->name == p.name && this->age == p.age)
{
return false;
}
return true;
}
string name;
int age;
};
void test01()
{
person p("TOM", 18);
cout << "p的姓名:" << p.name << " p的年龄:" << p.age << endl;
person p1("TOM", 20);
cout << "p1的姓名:" << p1.name << " p1的年龄:" << p1.age << endl;
person p2("TOM", 18);
cout << "p2的姓名:" << p2.name << " p2的年龄:" << p2.age << endl;
cout << "比较p与p1-------------------------" << endl;
cout << "重载==后的判断:" << endl;
if (p == p1) {
cout << "p和p1是相等的" << endl;
}
else {
cout << "p和p1是不相等的" << endl;
}
cout << "重载!=后的判断:" << endl;
if(p!=p1){
cout<<"p和p1是不相等的"<<endl;
}else{
cout<<"p和p1是相等的"<<endl;
}
cout << "比较p与p2-------------------------" << endl;
cout << "重载==后的判断:" << endl;
if (p == p2) {
cout << "p和p2是相等的" << endl;
}
else {
cout << "p和p2是不相等的" << endl;
}
}
int main()
{
test01();
return 0;
}
运行结果:
七、函数调用运算符重载
- 函数调用运算符()也可以重载
- 重载后的使用方式与函数的调用十分相似,因此称为仿函数
- 仿函数没有固定的写法,非常灵活
示例:
#include<iostream>
#include<math.h>
using namespace std;
// 函数调用运算符重载
class my_print{
public:
// 重载函数调用运算符
void operator()(string test)
{
cout<<test<<endl;
}
};
// 仿函数非常灵活,没有固定的写法
void myprint02(string test)
{
cout<<test<<endl;
}
// 一个加法的类
class myadd{
public:
int operator()(int num1,int num2)
{
return num1+num2;
}
};
void test01()
{
my_print mprint;
// 使用起来特别类似函数调用,因此称为仿函数
mprint("hello 重载函数调用运算符");// 重载了()类似于函数
myprint02("函数也可以直接放入字符串");
}
void test02()
{
myadd myADD;
int ret = myADD(10,20);
cout<<"自定义加法类的仿函数结果:"<<ret<<endl;
// 匿名函数对象 myadd(),使用完成后立即自动释放
cout<<myadd()(100,100)<<endl;
}
int main()
{
test01();
test02();
return 0;
}
运行结果: