六、运算符重载
/* Person operator+ (Person &p); */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Person { public: Person() {} Person(int a, int b) :A(a), B(b) {} // + 运算符重载, 成员函数 Person operator+ (Person &p) // 二元 { Person tmp; // 会走默认构造,所以需要默认构造 tmp.A = this->A + p.A; tmp.B = this->B + p.B; return tmp; } int A; int B; }; void test01() { Person p1(10, 20); Person p2(20, 30); Person p3 = p1 + p2; // 本质上是 p1.operate(p2), 但是已经封装成了 p1+p2 cout << "p3.A = " << p3.A << endl; // 30 cout << "p3.B = " << p3.B << endl; // 50 } int main() { test01(); return EXIT_SUCCESS; }
/* Person operator+ (Person &p1, Person &p2); Person operator+ (Person &p1, int val); */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Person { public: Person() {} Person(int a, int b) :A(a), B(b) {} int A; int B; }; // 利用全局函数进行 + 运算符重载 Person operator+ (Person &p1, Person &p2) // 二元 { Person tmp; // 会走默认构造,所以需要默认构造 tmp.A = p1.A + p2.A; tmp.B = p1.B + p2.B; return tmp; } // 加号运算符重载可以发生函数重载 Person operator+ (Person &p1, int val) { Person tmp; // 会走默认构造,所以需要默认构造 tmp.A = p1.A + val; tmp.B = p1.B + val; return tmp; } void test01() { Person p1(10, 20); Person p2(20, 30); Person p3 = p1 + p2; Person p4 = p1 + 30; cout << "p3.A = " << p3.A << endl; // 30 cout << "p3.B = " << p3.B << endl; // 50 cout << "p4.A = " << p4.A << endl; // 40 cout << "p4.B = " << p4.B << endl; // 50 } int main() { test01(); return EXIT_SUCCESS; }
/* ostream& operator<<(ostream &cout, Person &p1); 如果重载的时候,需要访问私有的成员属性,需要将全局函数设置为友元函数 */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Person { friend ostream& operator<<(ostream &cout, Person &p1); public: Person() {} Person(int a, int b) { this->A = a; this->B = b; } // 重载左移运算符 // 如果这样写,调用的时候为 p1.operate()...,也就是 p1<<不符合调用的时候 cout <<... 规则, // 所以重载左移运算符不能写在成员函数中 //void operator<<() //{ //} private: int A; int B; }; // 全局函数进行 左移运算符 // 根据 加号运算符重载 p1 + p2 , + 左右两边为两个参数, // 所以 cout << p1, << 运算符左右分别为 cout, p1 // 所以第一个参数 cout, 第二个参数 p1 // cout 的类型是 ostream ostream& operator<<(ostream &cout, Person &p1) { cout << "A = " << p1.A << " B = " << p1.B; // A,B都是public没问题,当A,B都是privite的时候,需要将这个函数加入友元函数 return cout; // 直接返回 cout, 这样 cout<<p1的返回值就是cout类型,再继续 << endl就不会有问题了 } void test01() { Person p1(10, 20); cout << p1 << endl; } int main() { test01(); return EXIT_SUCCESS; }
/* 前置递增返回引用,后置递增返回值 MyInteger& operator++(); 前置++ MyInteger operator++(int); 后置++ */ #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class MyInteger { friend ostream& operator<<(ostream&cout, MyInteger myInt); public: MyInteger() { this->num = 0; } // 前置++重载 /* 如果没有&, 就是MyInteger operator++(); 那么 cout<< ++(++myInt) << endl;的输出结果是2 但是 cout << myInt<< endl;的输出结果是 1, 因为返回的不是引用,第一次做完运算以后是一个临 时数据,第二次++操作的不是 myInt本体了,所以输出结果是 1 */ MyInteger& operator++() { this->num++; return *this; } // 后置++重载, 和前置++区别就是加了一个 int 占位参数的用途 MyInteger operator++(int) { // 先保存目前的数据 MyInteger tmp = *this; this->num++; // 返回原始数据 return tmp; } private: int num; }; ostream& operator<<(ostream&cout, MyInteger myInt) { cout << myInt.num ; return cout; } void test() { MyInteger myInt; cout << ++myInt << endl; // 1 前置++, 直接这样写的话,myInt是MyInteger类型,cout<<输出不识别,所以 需要左移运算符重载 cout << myInt++ << endl; // 1 后置++ cout << myInt << endl; // 2 } int main() { test(); return EXIT_SUCCESS; }
/* 如果 new 出来的对象,需要自己去 delete,有了智能指针,就能帮我们托管这个对象,对象的释放就不需要我们自己管了。为了让智能指针能够和普通的指针一样使用,需要重载 -> 和 * 两个指针操作 Person * operator->(); 重载 -> Person& operator*(); 重载 * */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Person { public: Person(int age) { this->Age = age; } ~Person() { cout << "Person析构" << endl; } void showAge() { cout << "年龄为 " << this->Age << endl; } int Age; }; // 智能指针 // 用来托管自定义类型的对象,让对象进行自动的释放 class smartPointer { public: smartPointer(Person * person) { this->person = person; } ~smartPointer() { cout << "智能指针析构" << endl; if (this->person != NULL) { delete this->person; this->person = NULL; } } // 重载 -> , 让智能指针对象能像Person对象一样使用 showAge()方法 Person * operator->() { return this->person; } // 重载 * Person& operator*() { return *this->person; } private: Person * person; }; void test01() { //Person p1(10); // 开辟在栈上,自动析构 //Person *p1 = new Person(10); // 开辟在堆上 //p1->showAge(); 可以直接调用 showAge()方法 //delete p1; // 需要自动释放 smartPointer sp(new Person(10)); // sp开辟到了栈上,会自动释放 sp->showAge();// 因为sp不存在在showAge方法, 所以需要重载 -> ,但是根据重载之后 sp->的返回值是指针, 所以实际上应该是 sp->->showAge(); 但是编译器自己帮我们优化了 // sp是一个指针, 所以希望能够 (*sp).showAge(), 所以需要重载 *运算符 (*sp).showAge(); } int main() { test01(); return EXIT_SUCCESS; }
/* 系统秒人给类提供 赋值运算符写法,是简单的值拷贝, 会出现导致如果类中有指向堆区的指针, 就可能出现深浅拷贝的问题, 所以需要重载 = 运算符, 因为存在链式赋值编程, 所以需要返回 *this; Person2& operator=(const Person2 &p); */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; class Person { public: Person(int a) { this->A = a; } int A; }; class Person2 { public: Person2(char *name) { this->pName = new char[strlen(name) + 1]; strcpy(this->pName, name); } ~Person2() { if (this->pName == NULL) { delete[] this->pName; this->pName = NULL; } } // 重载 = 运算符 Person2& operator=(const Person2 &p) { // 先判断原来已经堆区有内容,先释放 if (this->pName != NULL) { delete[] this->pName; this->pName = NULL; } this->pName = new char[strlen(p.pName) + 1]; strcpy(this->pName, p.pName); // 如果连等的话, 需要返回本体 return *this; } char *pName; }; void test01() { Person p1(10); Person p2(0); p2 = p1; // 一个类在创建的时候,默认会我们创建 默认构造,拷贝构造, 析构函数 还有一个 =赋值运算符(operator=) // 会进行简单的值传递, 所以会将 p1里面的值赋值给 p2 cout << "p2.A = " << p2.A << endl; // p2.A = 10 } void test02() { Person2 p3("wang"); Person2 p4("yong"); p4 = p3; cout << "p2.Name = " << p4.pName << endl; // wang // p4 = p3之后会进行值拷贝,将p3内的地址传递给p4,当p3析构以后,释放完以后, p4也需要释放,但是释放的空间已经为NULL // 所以就会报错,出现了深浅拷贝的问题, 所以需要重载等号运算符 Person2 p5("123"); p5 = p4 = p3; // 存在连等, 所以需要返回 本体 cout << "p5.Name = " << p4.pName << endl; // wang } int main() { test01(); test02(); return EXIT_SUCCESS; }
https://www.cnblogs.com/wangyong123/articles/16005731.html#_label2
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> using namespace std; // == 运算符重载 class Person { public: Person(string name, int age) { this->Name = name; this->Age = age; } bool operator==(Person &p) { if (this->Age == p.Age && this->Name == p.Name) { return true; } return false; } bool operator!=(Person &p) { if (this->Age == p.Age && this->Name == p.Name) { return false; } return true; } string Name; int Age; }; void test() { Person p1("wang", 27); Person p2("yong", 27); if (p1 == p2) { cout << "p1与p2相等" << endl; } else { cout << "p1和p2不相等" << endl; } if (p1 != p2) { cout << "p1与p2不相等" << endl; } else { cout << "p1和p2相等" << endl; } } int main() { test(); return EXIT_SUCCESS; }
八、函数调用运算符重载(())
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> using namespace std; // == 运算符重载 class MyPrint { public: void operator()(string text) { cout << text << endl; } }; class MyAdd { public: int operator()(int a, int b) { return a + b; } }; void test() { MyPrint myprint; myprint("Hello World"); // 仿函数 MyAdd myadd; cout << myadd(10, 20) << endl; cout << MyAdd()(20, 30) << endl; // 匿名对象 } int main() { test(); return EXIT_SUCCESS; }
九、逻辑运算符一般不重载(&&、||)
不要重载 &&,|| 运算符, 因为无法实现短路规则
十、符号重载总结
=, [], (), -> 操作运算符只能通过成员函数进行重载
<<, >>只能通过区研究院函数配合友元函数进行重载
不要重载 && 和 ||, 因为无法实现短路规则
运算符 建议使用 所有的一元运算符 成员 =,(), ->, * 必须是成员 +=,-=,/=,^=,&=,!=,%=,>>=,<<= 成员 其他二元运算符 非成员
十一、运算符重载练习:字符串的封装
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> using namespace std; class MyString { friend ostream& operator<<(ostream &cout, MyString & str); friend istream& operator>>(istream &cin, MyString &str); public: MyString(char * str); MyString(const MyString & str); ~MyString(); // = 运算符重载 MyString& operator=(const char *str); MyString& operator=(const MyString &str); // [] 运算符重载 char& operator[](int index); // + 运算符重载 MyString operator+(const char * str); MyString operator+(const MyString & str); // == 运算符重载 bool operator==(const char *str); bool operator==(const MyString &str); private: char *pString; //执行堆区的指针 int Size; // 字符串大小 };
#include "MyString.h" MyString::MyString(char * str) { cout << "有参构造调用" << endl; this->pString = new char[strlen(str) + 1]; strcpy(this->pString, str); this->Size = strlen(str); } MyString::MyString(const MyString & str) { this->pString = new char[strlen(str.pString) + 1]; this->Size = str.Size; strcpy(this->pString, str.pString); } MyString::~MyString() { if (this->pString == NULL) { delete[] this->pString; this->pString = NULL; } } // 左移运算符重载 ostream& operator<<(ostream &cout, MyString & str) { cout << str.pString; return cout; } // 右移运算符重载 istream& operator>>(istream &cin, MyString &str) { // 先把原有的内容清空 if (str.pString != NULL) { delete [] str.pString; str.pString = NULL; } // 让用户输入内容 char buff[1024]; cin >> buff; // 把用户输入的字符串赋值给 pString str.pString = new char[strlen(buff) + 1]; strcpy(str.pString, buff); str.Size = strlen(buff); return cin; } // =运算符重载 MyString& MyString::operator=(const char *str) { if (this->pString != NULL) { delete[] this->pString; this->pString = NULL; } this->pString = new char[strlen(str) + 1]; strcpy(this->pString, str); return *this; } MyString& MyString::operator = (const MyString &str) { if (this->pString != NULL) { delete[] this->pString; this->pString = NULL; } this->pString = new char[strlen(str.pString) + 1]; strcpy(this->pString, str.pString); return *this; } char& MyString::operator[](int index) { return this->pString[index]; } MyString MyString::operator + (const char * str) { // 计算返回的字符串开辟的大小 int newSize = this->Size + strlen(str) + 1; char *tmp = new char[newSize]; memset(tmp, 0, newSize); // 字符串拼接 strcat(tmp,this->pString); strcat(tmp, str); MyString newStr(tmp); delete[] tmp; return newStr; } MyString MyString::operator + (const MyString & str) { // 计算返回的字符串开辟的大小 int newSize = this->Size + strlen(str.pString) + 1; char *tmp = new char[newSize]; memset(tmp, 0, newSize); // 字符串拼接 strcat(tmp, this->pString); strcat(tmp, str.pString); MyString newStr(tmp); delete[] tmp; return newStr; } bool MyString::operator == (const char *str) { if (strcpy(this->pString, str) == 0 && this->Size == strlen(str)) { return true; } return false; } bool MyString::operator == (const MyString &str) { if (strcpy(this->pString, str.pString) == 0 && this->Size == strlen(str.pString)) { return true; } return false; }
#include "MyString.h" void test() { MyString str = "abc"; // 重载左移运算符 cout << str << endl; cout << "请输入 str 新的内容" << endl; // 右移运算符重载 cin >> str; cout << "str 新的内容是 " << str << endl; MyString str2(str); MyString str3 = ""; // = 运算符重载 str3 = str2; cout << "str3 = " << str3 << endl; str3 = "aaa"; cout << "str3 = " << str3 << endl; // [] 运算符重载 cout << "str3 第一个位置为 " << str3[0] << endl; str3[0] = 'z'; cout << "str3 第一个位置为 " << str3[0] << endl; MyString str4 = ""; // + 运算符重载 str4 = str2 + str3; cout << "str4 = " << str4 << endl; // ==运算符重载 if (str3 == str4) { cout << "str3与str4相等" << endl; } else { cout << "str3与str4不相等" << endl; } } int main() { test(); return EXIT_SUCCESS; }