阅读量:0
目录
一、示例
如果我想实现以下代码,按照下面的写法是不能正常运行的。
class Person { public: int m_A; int m_B; }; Person p1; p1.m_A = 10; p1.m_B = 10; Person p2; p2.m_A = 10; p2.m_B = 10; Person p3; p3 = p1 + p2;
按照以上学过的内容,可以自己写成员函数,实现两个对象相加属性后返回新对象
Person add(Person &p) { Person temp; temp.m_A = this -> m_A + p.m_A; temp.m_B = this -> m_B + p.m_B; return temp; //返回值会创建一个新的对象出来 }
二、operator
编译器起一个通用重载的名称:operator
对已有运算符重新定义,赋予另一种功能,适应不同的数据类型
注意:
①对于内置的数据类型的表达式的运算符是不可能改变的:int、float、double
②不要滥用运算符重载:把加法写成减法...
三、加减号重载
* 通过成员函数重载 + 号运算符
class Person { public: 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; }; void test() { Person p1; p1.m_A = 10; p1.m_B = 10; Person p2; p2.m_A = 10; p2.m_B = 10; //原理:Person p3 = p1.operator+(p2); //简化如下: Person p3 = p1 + p2; }
* 通过全局函数重载 + 号运算符
class Person { public: int m_A; int m_B; }; Person operator+ (Peerson &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; } void test() { Person p1; p1.m_A = 10; p1.m_B = 10; Person p2; p2.m_A = 10; p2.m_B = 10; //原理:Person p3 = operator+ (p1,p2); //简化如下: Person p3 = p1 + p2; }
* 运算符函数重载
class Person { public: int m_A; int m_B; }; Person operator+ (Peerson &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 = 10; //原理:Person p3 = operator+ (p1,num); //简化如下:person + int Person p3 = p1 + 10 ; }
四、左移运算符重载 ( << )
* 使得cout可以输出person类数据
class Person { friend ostream & operator<<(ostream &cout,Person p); public: Person(int a, int b) { m_A = a; m_B = b; } private: //利用成员函数来重写左移运算符 //如果不知道该函数应该返回什么 可以先写一个void做测试 //通常不会使用成员函数重载<<运算符,因为无法实现 cout在左侧 会出现 p << cout 的简化方式 //void operator<<( cout ) //{} int m_A; int m_B; }; //只能利用全局函数重载左移运算符 //不清楚cout是什么类型,可以右键跳转定义 //ostream标准输出流对象,因为全局只有一个,所以需要用引用方式传过来 ostream & operator<<(ostream &cout,Person p) //本质:operator<< (cout,p) 简化形式:cout << p { cout << "m_A = " << p.m_A << " m_B = " << p.m_B; return cout; } void test() { Person p(10,10); //调用完返回cout就可以链式编程不断追加 cout << p << endl; }
五、递增运算符重载(++)
可以利用该方法写一个int数据类型
** 注意前置递增和后置递增的返回类型区别
class MyInt { friend ostream& operator<<(ostream& cout,MyInt mint); public: MyInt() { m_Num = 0; } //成员函数重载前置++运算符 //返回引用不返回值,为了一直对一个数据进行递增操作,而非对一个新的数据进行操作 MyInt& operator++() { //先进行++运算 m_Num++; //再将自身作为返回 return *this; //this指向自身,*将其解引用 } //成员函数重载后置++运算符 //int代表的是占位参数,用于区分前置和后置递增,只能写int其他不行 //后置需要返回值,不能返回应用,因为temp是局部对象,返回引用是非法操作 MyInt operator++(int) { //先返回结果(记录当时结果) MyInt temp = *this; //再进行递增 m_Num++; //最后将结果返回 return temp; } private: int m_Num; }; ostream& operator<<(ostream& cout,MyInt mint) { cout << mint.m_Num; return cout; } void test() { MyInt mint; cout << mint << endl; // 0 cout << ++mint << endl; // 1 cout << mint++ << endl; // 1 cout << mint << endl; // 2 }
六、赋值运算符重载 (=)
c++编译器至少给一个类添加4个函数:
①默认构造函数:无参,函数体为空
②默认析构函数:无参,函数体为空
③默认拷贝构造函数:对属性进行值拷贝
④赋值运算符operator=,对属性进行值拷贝
class Person { public: Person(int age) { m_Age = new int(age); //将age数据创建在堆区,并使用指针维护该数据 } //堆区数据由程序员手动创建及释放 ~Person() { if(m_Age != NULL) { delete m_Age; m_Age = NULL; } } int *m_Age; }; void test() { Person p1(18); Person p2(20); //该方法为浅拷贝 会出现p1p2重复释放 程序崩溃 p2 = p1; //利用深拷贝解决该问题 cout << "p1的年龄为:" << *p1.m_Age << endl; cout << "p2的年龄为:" << *p2.m_Age << endl; }
** 重载赋值运算符
class Person { public: Person(int age) { m_Age = new int(age); //将age数据创建在堆区,并使用指针维护该数据 } //重载赋值运算符 Person& operator=(Person &p) { //编译器提供的是浅拷贝:m_Age = p.m_Age; 不可取 //先判断是否有属性在堆区,如果有需要先释放干净,再深拷贝 if(m_Age != NULL) { dekete m_Age; m_Age = NULL; } m_Age = new(*p.m_Age); return *this; } //堆区数据由程序员手动创建及释放 ~Person() { if(m_Age != NULL) { delete m_Age; m_Age = NULL; } } int *m_Age; }; void test() { Person p1(18); Person p2(20); Person p3(30); cout << "p1的年龄为:" << *p1.m_Age << endl; cout << "p2的年龄为:" << *p2.m_Age << endl; cout << "p3的年龄为:" << *p3.m_Age << endl; }
七、关系运算符重载(> < = !=)
重载关系运算符,可以让两个自定义类型对象进行对比操作
class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; }; //重载关系运算符==号 bool operator==(Person &p) { if(this->m_Name == p.m_Name && this->m_Age == p.Age) { return true; } return false; } //重载关系运算符!=号 bool operator==(Person &p) { if(this->m_Name == p.m_Name && this->m_Age == p.Age) { return false; } return true; } string m_Name; int m_Age; }; void test() { Person p1("Tom", 18); Person p2("Tom", 18); if(p1 == p2) { cout << "p1和p2是相等的" << endl; } else { cout << "p1和p2是不相等的" << endl; } }
八、函数调用运算符重载
①函数调用运算符()可以重载
②由于重载后使用的方法像函数的调用,故称为仿函数
③仿函数没有固定写法
class MyPrint { public: void operator()(string text) { cout << text << endl; } }; void test01() { //重载()操作符,仿函数 MyPrint myFunc; myFunc(“hello!”); } class MyAdd { public: int operator()(int num1, int num2) { return num1 + num2; } }; void test02() { MyAdd myadd; int ret = myadd(1,2); cout << "ret=" << ret << endl; //匿名函数对象 cout << MyAdd()(100, 100) << endl; }
查漏补缺:
函数重载和函数重写的区别:https://blog.csdn.net/inter_peng/article/details/53940179
递增运算符复习:
int a = 10; cout << ++a << endl; // 11 cout << a << endl; //11 int b = 10; cout << b++ << endl; //10 cout << b << endl; //11
new关键字使用方法:https://blog.csdn.net/qq_15345177/article/details/88066050