C++运算符重载


?

C++运算符重载

?

对于内置数据类型而言可以进行正常的运算符使用,而对于自定义的数据类型则无法与之匹配。

对于这个问题我们一般使用函数来解决,而编译器为我们提供了一个标准的命名方式可以简化调用方式,实现自定义数据类型的运算符使用,我们称其为运算符重载

关键字:operator+运算符

 

?
? ?

重载方式

?

成员函数重载(在类内)

全局函数重载(在全局区)

 

?
?

 

?

加号运算符重载

?

 

 

参考代码:

#include //关键词 operator
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 test01()
{
Person P1;
P1.m_A = 10;
P1.m_B = 10;
?
Person P2;
P2.m_A = 10;
P2.m_B = 10;
?
//简化调用:
Person P3 = P1 + P2;
?
//成员函数重载本质调用:
//Person P3 = P1.operator + (P2);
?
//全局函数重载的本质调用:
//Person P3 = operator+(P1, P2);
?
//运算符重载,也可以发生函数重载
Person P4 = P1 + 10; //Person + int
?
cout << "P3.m_A=" << P3.m_A << endl;
cout << "P3.m_B=" << P3.m_B << endl;
?
cout << "P4.m_A=" << P4.m_A << endl;
cout << "P4.m_B=" << P4.m_B << endl;
}
?
?
int main()
{
?
test01();
?
system("pause");
return 0;
}

 

 

 

?
?

 

?

左移运算符重载

?

 

参考代码:

#include 
using namespace std;
?
//可以输出自定义数据类型
class Person
{
friend ostream& operator<<(ostream &cout, Person &P); //全局函数做友元
?
public: //在定义一个默认构造函数初始化
Person()
{
m_A = 10;
m_B = 10;
}
?
?
//更改一下public:
private: //一般成员属性用私有权限(使用友元!)
?
//利用成员函数来重载一个 << 运算符
//一开始使用:void operator<<(Person &P)时,调用时 P.opertor<<(P)显然不符合
//现在:简化版本 P << cout; 显然先后次序发生了变化(看不懂就参考一下 加号的 成员函数重载简化)
//不会利用成员函数重载 << 运算符,因为无法实现 cout在左侧
/*void operator<<(cout)
{
?
}*/
?
int m_A;
int m_B;
};
?
?
//这个重载函数是没有返回值的
//只能利用全局运算符重载左移运算符 cout的数据类型可以通过查看定义来看
ostream& operator<<(ostream &cout, Person &P) //本质 operator<<(cout,P) 简化 cout << P
{
cout << "m_A = " << P.m_A << "m_B = " << P.m_B;
return cout; //引用做函数返回值 函数调用可以作为左值 此处是为了进行链式追加
?
//最后注意:引用本身就是取别名,所以这里使用out也可以
}
?
void test01()
{
Person P;
?
//为了实现直接输出对象,而重载左运算符
cout << P << endl << "Hello world!" << endl; //想要链式追加?
}
?
?
int main()
{
?
test01();
?
system("pause");
return 0;
}

 

 

?
?

 

?

递增运算符重载

?

 

#include 
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; //myint是创建的一个对象
?
cout << ++(++myint) << endl; //此处需要实现myint的 左移位运算 与 自增运算
cout << myint << endl; //显然通过此行输出我们可以看出
//如果返回类型不是一个引用 那么就不是在同一个数据上进行这两次自增操作
}
?
//后置递增
void test02()
{
MyInteger myint;
?
cout << myint++ << endl;
?
cout << myint << endl;
}
?
int main()
{
//前置
//test01();
?
//后置
test02();
?
?
//在内置的此类操作中 两次前置递增 都是在同一个数据上进行
/*int a = 0;
?
cout << ++(++a) << endl;
cout << a << endl;*/
?
system("pause");
return 0;
}

 

 

?
?

 

?

递减运算符重载

?

 

参考代码:

#include 
using namespace std;
?
class MyInteger
{
friend ostream& operator<<(ostream &cout, MyInteger myint); //全局函数做友元
public:
?
MyInteger() //自定义默认构造函数,初始化成员变量数值
{
m_Num = 0;
}
?
//前置递减
MyInteger& operator--()//此处返回类的引用 是为了进行链式编程
{
m_Num--;
?
return *this;
}
?
//后置递减
MyInteger operator--(int) //占位形参用于区分 前置与后置
{
MyInteger temp = *this;
?
m_Num--;
?
return temp;
}
?
private:
int m_Num;
};
?
//重载<<运算符
ostream& operator<<(ostream &cout,MyInteger myint )//返回值为cout的引用使其可以作为左值
{
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()
{
?
//test01();
?
test02();
?
system("pause");
return 0;
}

 

 

?
?

 

?

赋值运算符重载

?

 

参考代码:

#include 
using namespace std;
?
//C++编译器至少给一个类添加4个函数
//1、默认构造函数(无参,函数体为空)
//2、默认析构函数(无参,函数体为空)
//3、默认拷贝函数,对属性进行值拷贝
?
//4、赋值运算符operator=,对属性进行值拷贝(也会和浅拷贝一样,引起堆区内存重复释放)
//即:简单拷贝,会连着将地址值也拷贝到另一个对象里,
//当我们提供的成员属性是堆区的地址时,需要借助析构函数进行内存释放,此时就会引起堆区内存的重复释放
?
?
//赋值运算符重载
class Person
{
public:
?
Person(int age)
{
m_Age = new int(age); //用关键词 new 创建在了堆区
}
?
~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 P1(18);
?
Person P2(20);
?
Person P3(30);
?
P3 = P2 = P1; //赋值操作
?
cout << "P1的年龄为:" << *P1.m_Age << endl;
?
cout << "P2的年龄为:" << *P2.m_Age << endl;
?
cout << "P3的年龄为:" << *P3.m_Age << endl;
?
}
?
int main()
{
test01();
?
?
//对于内置数据类型支持连续赋值
/*int a = 10;
int b = 20;
int c = 30;
?
c = b = a;
?
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;*/
?
system("pause");
return 0;
}

 

?
?

 

?

关系运算符重载

?

 

参考代码:

#include 
#include
using namespace std;
?
//重载关系运算符
?
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
?
//重载 == 号
bool operator==(Person &P)
{
if (P.m_Age == this->m_Age&&P.m_Name == this->m_Name)
{
return true;
}
else
{
return false;
}
}
?
//重载 != 号
bool operator!=(Person &P)
{
if (P.m_Age != this->m_Age || P.m_Name != this->m_Name)
{
return true;
}
else
{
return false;
}
}
?
string m_Name;
int m_Age;
};
?
//测试 == 的重载
void test01()
{
Person P1("张三", 18);
?
Person P2("张三", 18);
?
if (P1 == P2)
{
cout << "P1与P2是相等的" << endl;
}
else
{
cout << "P1与P2是不相等的" << endl;
}
}
?
//测试 != 的重载
void test02()
{
Person P1("张三", 18);
?
Person P2("张三", 18);
?
if (P1 != P2)
{
cout << "P1与P2不是相等的" << endl;
}
else
{
cout << "P1与P2是相等的" << endl;
}
}
?
int main()
{
?
test01();
?
test02();
?
system("pause");
return 0;
}

 

 

?
?

 

?

函数调用运算符重载

?

 

参考代码:

#include 
#include
using namespace std;
?
//函数调用运算符 () 重载
//由于重载后使用的方式非常像函数的调用,因此成为仿函数
//仿函数没有固定的写法,非常灵活 (在后续的STL里面涉及的多)
?
//打印输出类
class MyPrint
{
public:
?
//重载函数调用运算符 //成员函数重载
void operator()(string test)
{
cout << test << endl;
}
?
?
};
?
void MyPrint02(string test)
{
cout << test << endl;
}
?
void test01()
{
MyPrint myPrint;
myPrint("hello world"); //重载过后一个对象进行调用 由于使用起来非常类似一个函数调用,因此称为仿函数
?
MyPrint02("hello world"); //一个函数调用
}
?
//仿函数非常灵活,没有固定的写法
?
//加法类
class MyAdd
{
public:

int operator()(int num1,int num2) //比较两个仿函数的写法 形式不是唯一的(参数个数与返回值等)
{
return num1 + num2;
}
};
?
void test02()
{
MyAdd myadd;
int ret = myadd(100, 100);
cout << "ret = " << ret << endl;
?
//匿名函数对象
//回忆匿名对象 MyAdd() 等价于 本类的对象名
//因此处重载了()使得这个匿名对象进行了仿函数调用 所以称其为匿名函数对象
cout << MyAdd()(100, 100) << endl; //先创建一个对象执行后直接释放(参考构造函数的调用)
?
}
?
int main()
{

//test01();
?
test02();
?
system("pause");
return 0;
}
 

相关