目录
--让类类型的对象像基本数据类型一样去操作,例如,可以实现对象+,-,*,/,%,==,! = [] () << >>等
返回类型 operator 运算符(参数列表) 比如:operator=(const A&str)
返回值类型 类名::operator重载的运算符(参数表){……}
operator是关键字,它与重载的运算符一起构成函数名。因函数名的特殊性,C++编译器可以将这
类函数识别出来。
是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该重载的运算符时调用此函数。这个函数叫做运算符重载函数,通常为类的成员函数。
如何实现两个同类的对象相加?
- class A
- {
- public:
- A(int i=0):m_i(i){}
- private:
- int m_i;
- };
- void main()
- {
- A a(5), b(7);
- }
我们发现两个A类对象并不能直接相加。
- class A
- {
- public:
- A(int i=0):m_i(i){}
- private:
- int m_i;
- };
-
- class STR
- {
- public:
- STR(const char* str = "\0")
- {
- m_str = new char[strlen(str) + 1];
- strcpy_s(m_str, strlen(str) + 1, str);
- }
- private:
- char* m_str;
- };
-
- void main()
- {
- A a(5), b(7);
- int aa = 5, bb = 7;
- cout << aa + bb << endl;
-
- STR s("1234567");
- string str = "123456";
- string s1 = "123", s2 = "456";
- string s3 = s1 + s2;
- cout << str << endl;
- str[3] = 'k';
- cout << str << endl;
- cout << "s3= " << s3 << endl;
- //s[2] = 'k';
- }
我们发现如果将我们写的类的内容,直接写为int这一大类的内容相加的时候是可以实现的,于是我们可以通过之前的接口,将A类的i直接获得,变为两个int类的相加
- class A
- {
- public:
- A(int i = 0,int j=0) :m_i(i),m_j(j)
- {
-
- }
- const int& GetI()const
- {
-
- return m_i;
- }
- const int& GetJ()const
- {
- return m_j;
- }
- A ADD(const A& b)
- {
- return A(m_i+b.m_i,m_j+b.m_j);
- }
- void Print()
- {
- cout << m_i << " " << m_j << endl;
- }
- private:
- int m_i;
- int m_j;
- };
-
- void main()
- {
- A a(5), b(7);
- //cout << a.m_i + b.m_i << endl;//error//本质上就是把对象的数据成员进行相加
- cout << a.GetI() + b.GetI() << endl;
- cout << a.GetJ() + b.GetJ() << endl;
- a.ADD(b).Print();
- }
看起来不直观,可读性低
并且当类的成员越来越多时,这样显得非常麻烦
3.前提:
- void main()
- {
- int a = 10, b = 3;
- int c = 0;
- c = a + b;
- //a+b=c;//error
- ++a = c;
- //b++=13;//error
- cout << a << endl;
- (a = b) = c;
- }
1.c = a + b;//从a的内存空间把a的值取出来,从b的内存空间把b的值取出来,把相加过的值放在c的空间
2.a+b=c;//error//从c的内存空间把c的值取出来,a+b(的空间是临时空间,表达式结束,空间就释放了)没有确定的(永久)空间存放c
3.++a = c;//(现在的a=11=执行过表达式后的a的值)将c放到a的存储单元
4.//b++=13;//error//(b=3,b++=4,值不一样,b++没有确定空间)
4.如何重载?
- class A
- {
- public:
- A(int i=0):m_i(i)//构造函数可作为类型转换
- {
-
- }
- void Print()
- {
- cout << m_i << endl;
- }
- A operator+(const A&b)//本质是实现对象的数据成员的加法
- {
- return m_i + b.m_i;
- }
- //A operator-(const A& a)//b-a b.operator-(a)本质是实现对象的数据成员的减法
- //{
- // return this->m_i - a.m_i;
- //}
- A operator-(const A& s)//b-a b.operator-(a)本质是实现对象的数据成员的减法
- {
- return this->m_i - s.m_i;
- }
- A& operator++()//++a a.++
- {
- ++m_i;//将a自己的数据成员进行修改
- return *this;//修改完后,返回自己本身
- }
- /*
- * b++,表达式的值是,b没加的值,执行完成后,b+1,所有在重载之后++,得体现两种值
- */
- A operator++(int)//int 没有实际性作用,只是为了区分前置++
- {
- int t = m_i;//保存自己
- m_i = m_i + 1;//+1
- return t;//返回没加以前保存的值
- //return m_i++//等价与上面三句话
- }
- private:
- int m_i;
- };
-
- int main()
- {
- A a(2), b(6);
- (a + b).Print();
- (b - a).Print();
- (a - b).Print();
- (++a).Print();
- (b++).Print();
- b.Print();
-
- }
(a + b).Print();//a.+(b)//成员形式//(a,b)//友元
(b - a).Print();//b.-(a);
(a - b).Print();//a.-(b)
(++a).Print();//3
(b++).Print();//b加之前//6
b.Print();//上式+1 7
5.默认
如果程序员没有提供赋值运算符,则类会提供一个默认的,默认的功能为:
用右边的对象的数据成员依次给左边对象的数据成员赋值
- class A
- {
- public:
- A(int i = 0, int j = 0) :m_i(i), m_j(j)
- {
- }
- void Print()
- {
- cout << m_i << " " << m_j << endl;
- }
- private:
- int m_i;
- int m_j;
- };
-
- void main()
- {
- A a(2, 6);
- A b;
- a.Print();
- b.Print();
- b = a;
- b.Print();
- }
a.Print();// 2 6
b.Print();// 0 0
b = a;// 2 6用a的值重新给b赋值,调用了默认的赋值运算符重载函数
b.Print();
6.指针作为数据成员
- class Person
- {
- public:
- Person(const char*name="\0")
- {
- m_name = new char[strlen(name) + 1];
- strcpy_s(m_name, strlen(name) + 1, name);
- }
- void Print()
- {
- cout << m_name << endl;
- }
- ~Person()
- {
- delete[]m_name;
- m_name = NULL;
- }
- Person& operator=(const Person& s)//析构+拷贝构造
- {
- if (this == &s)//判断自赋值
- return *this;
- delete[]m_name;
- m_name = new char[strlen(s.m_name) + 1];
- strcpy_s(m_name, strlen(s.m_name) + 1, s.m_name);
-
- return *this;
- }
- private:
- char* m_name;
- };
-
- void main()
- {
- Person p1("lisi");
- Person p2("11");
- p1.Print();
- p2.Print();
- p2 = p1;
- p2.Print();
- }
总结:
如果有指针作为数据成员,则赋值运算符重载也要写出来,让两个而不同的对象的指针分别指向内存单元,不过里面的内容保持相同
* 赋值=能作为左值,所以引用返回
if (this == &s) //判断自赋值
return *this;
//先将左边对象原本的内存空间释放掉
delete[]m_name;
//接着开辟和右边对象s相同大小的内存单元
m_name = new char[strlen(s.m_name) + 1];
strcpy_s(m_name, strlen(s.m_name) + 1, s.m_name);
p2 = p1; //用p1给p2重新赋值,如果调用默认的赋值重载,则让p2的指针重新指向了p1的指针,p1和p2的指针指向同一块空间,但是p2原本的空间还在
7.字符串重载
- class STR
- {
- public:
- STR(const char* str = "\0")
- {
- m_str = new char[strlen(str) + 1];
- strcpy_s(m_str, strlen(str) + 1, str);
- }
- STR(const STR& s)
- {
- m_str = new char[strlen(s.m_str) + 1];
- strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);
- }
- ~STR()
- {
- cout << "~STR " << m_str << endl;
- if (m_str != NULL)
- {
- delete[]m_str;
- m_str = NULL;
- }
- }
- STR operator+(const STR& s)//a+b 其实就是将两个对象中的字符串合并
- {
- char* temp = new char[strlen(m_str) + strlen(s.m_str) + 1];
- strcpy_s(temp, strlen(m_str)+1, m_str);
- strcat_s(temp,strlen(m_str)+strlen(s.m_str)+1, s.m_str);
- STR ss(temp);
- delete[]temp;
- temp = NULL;
- return ss;
- }
- STR& operator=(const STR& s)
- {
- if (this == &s)
- return *this;
- delete[]m_str;
- m_str = new char[strlen(s.m_str) + 1];
- strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);
- return *this;
- }
- void Print()
- {
- cout << "m_str = "<
- }
- char& operator[](int index)
- {
- if (index >= 0 && index < strlen(m_str)) //"1234"
- return m_str[index];
- }
- int operator==(const STR& s)
- {
- return strcmp(m_str, s.m_str)==0;
- }
- private:
- char* m_str;
- };
- void main()
- {
- STR a("111"), b("222");
- cout << "a:" << endl;
- a.Print();
- cout << "b:" << endl;
- b.Print();
- STR c = a + b;//拷贝构造 111222
- cout << "c:" << endl;
- c.Print();//111222
- STR d;
- d = c;//赋值=运算符重载
- cout << "d:" << endl;
- d.Print();//111222
- c[5] = 'h';
- cout << "c[5]" << endl;
- cout << c[5] << endl;//11122h
- cout << "c:" << endl;
- c.Print();
- cout << "a==b" << endl;
- cout << (a == b) << endl;//0
- cout << "a!=b" << endl;
- cout << (a != b) << endl;//1
- }
8.友元重载:重载输出<<运算符
cout--ostream类的对象
cin--istream类的对象
cout << a;
一般情况下运算符可以解析成下面两种形式
1.cout.<<(a) ostream类中重载了<<,程序员不能修改
2.<<(cout,a) 可以在程序员自己定义的类中将<<重载成友元
cout< cout< (cout<
friend ostream& operator<<(ostream &out,A &a)
- class Magic
- {
- double x;
- public:
- Magic(double d=0.00):x(fabs(d)){}
- Magic operator+(Magic c)
- {
- return Magic(sqrt(x * x + c.x * c.x));
- }
- friend ostream& operator << (ostream& os, Magic c);
- };
- ostream& operator << (ostream& os, Magic c)
- {
- return os << c.x;
- }
- void main()
- {
- Magic ma;
- cout << ma << ',' << Magic(-8) << "," << ma + Magic(-3) + Magic(-4);
- }
9.运算符重载函数的总结
1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右 操作数作为函数的实参。
2、当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个 或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函 数,而右操作数是该函数的参数。
3、单目运算符“++”和“--”存在前置与后置问题。 前置“++”格式为: 返回类型 类名::operator++(){……} 而后置“++”格式为: 返回类型 类名::operator++(int){……} 后置“++”中的参数int仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。
4、C++中只有极少数的运算符不允许重载。
还有 # , ## , // , / * */
10.重载运算符有以下几种限制
不可臆造新的运算符.
不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数.
运算符重载不宜使用过多.
重载运算符含义必须清楚,不能有二义性
-
相关阅读:
spring之AOP的概念及简单案例
迭代器 Iterator
Leetcode2-两数相加代码详解
weak的底层原理
sqllab第三关通关笔记
APISIX、APISIX Dashboard搭建及插件使用
后台管理系统SQL注入漏洞
抛弃BeanUnits.copyProperties三部曲
C# 6.0 添加和增强的功能【基础篇】
牛客网《剑指offer》专栏刷题练习|锻炼递归思想|练习栈的使用
-
原文地址:https://blog.csdn.net/m0_59052131/article/details/127622009