{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# C++ 运算符重载" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. 运算符重载简介" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① 运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。\n", "\n", "② 对于内置的数据类型的表达式的运算符是不可能改变的。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. 加号运算符重载" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① 加号运算符作用:实现两个自定义数据类型相加的运算。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "\n", "//加号运算符重载\n", "class Person\n", "{\n", "public:\n", "\n", " //1、成员函数重载+号\n", " Person operator+(Person& p)\n", " {\n", " Person temp;\n", " temp.m_A = this->m_A + p.m_A;\n", " temp.m_B = this->m_B + p.m_B;\n", " return temp;\n", " }\n", " int m_A;\n", " int m_B;\n", "};\n", "\n", "/*\n", "//全局函数重载+号\n", "Person operator+(Person &p1, Person &p2)\n", "{\n", " Person temp;\n", " temp.m_A = p1.m_A + p2.m_A;\n", " temp.m_B = p1.m_B + p2.m_B;\n", " return temp;\n", "}\n", "*/\n", "\n", "//函数重载的版本\n", "Person operator+(Person& p1, int num)\n", "{\n", " Person temp;\n", " temp.m_A = p1.m_A + num;\n", " temp.m_B = p1.m_B + num;\n", " return temp;\n", "}\n", "\n", "void test01()\n", "{\n", " Person p1;\n", " p1.m_A = 10;\n", " p1.m_B = 10;\n", " Person p2;\n", " p2.m_A = 10;\n", " p2.m_B = 10;\n", "\n", " //成员函数重载本质调用 \n", " //Person p3 = p1.operator+(p2);\n", " \n", " //全局函数重载本质调用 \n", " //Person p3 = operator+(p1,p2);\n", " \n", " Person p3 = p1 + p2; //重载本质被简化后的形式\n", "\n", " //运算符重载,也可以发生函数重载\n", "\n", " Person p4 = p1 + 10; //Person + int\n", "\n", " cout << \"p3.m_A:\" << p3.m_A << endl;\n", " cout << \"p3.m_B:\" << p3.m_B << endl;\n", "\n", " cout << \"p4.m_A:\" << p4.m_A << endl;\n", " cout << \"p4.m_B:\" << p4.m_B << endl;\n", "\n", "}\n", "\n", "\n", "int main()\n", "{\n", " test01();\n", "\n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - p3.m_A:20 \n", " - p3.m_B:20 \n", " - p4.m_A:20 \n", " - p4.m_B:20 \n", " - 请按任意键继续. . ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. 左移运算符重载" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① 左移运算符重载:可以输出自定义数据类型。\n", "\n", "② 重载左移运算符配合友元可以实现自定义数据类型。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "\n", "//左移运算符\n", "class Person\n", "{\n", "\n", " friend ostream& operator<<(ostream& out, Person& p);\t\n", "\n", "public:\n", " Person(int a, int b)\n", " {\n", " m_A = a;\n", " m_B = b;\n", " }\n", "\n", " /*\n", " //利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p << cout\n", " //成员函数不能利用重载<<运算符,因为无法实现cout在左侧\n", " //当不知道返回值是什么类型的时候,可以先写个void,以后再改\n", " void operator<<(Person& p)\n", " {\n", " \n", " }\n", " */\n", " \n", "private:\n", " int m_A;\n", " int m_B;\n", "};\n", "\n", "//只能利用全局函数重载左移运算符\n", "//如果返回类型为void,那么就无法无限追加,也没有办法在后面添加换行符\n", "ostream & operator<<(ostream &cout, Person &p) //本质 operator << (cout , p) , 简化 cout << p\n", " //cout是别名,这里可以取out、kn...\n", " //cout为ostream输出流数据类型 \n", "{\n", " cout << \"m_A= \" << p.m_A << \" m_B=\" << p.m_B;\n", " return cout;\n", "}\n", "\n", "void test01()\n", "{\n", " Person p(10,10);\n", "\n", " cout << p << \" hello world\" << endl;\n", "}\n", "\n", "\n", "int main()\n", "{\n", " test01();\n", "\n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - m_A= 10 m_B=10 hello world \n", " - 请按任意键继续. . ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. 递增运算符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① 递增运算符重载:通过重载递增运算符,实现自己的整型数据。\n", "\n", "② 前置递增返回的是引用,后置递增返回的是值。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "\n", "//重载递增运算符\n", "\n", "class MyInteger\n", "{\n", " friend ostream& operator<<(ostream& cout, MyInteger myint);\n", "\n", "public:\n", " MyInteger()\n", " {\n", " m_Num = 0;\n", " }\n", " \n", " //重载前置++运算符,返回引用是为了一直对一个数据进行递增操作,而返回值并不是一直对一个数据进行递增操作 \n", " MyInteger& operator++()\n", " {\n", " //先进行++运算\n", " m_Num++;\n", "\n", " //再将自身做一个返回\n", " return *this; //把自身做一个返回\n", " }\n", "\n", " //重载后置++运算符 int代表占位参数,可以用于区分前置和后置递增\n", " //后置递增不能返回引用,因为temp是局部变量,如果返回temp,当程序运行完后变量就释放了,再调用temp就是非法操作了 \n", " MyInteger operator++(int)\n", " {\n", " //先记录当时结果\n", " MyInteger temp = *this;\n", " //后 递增\n", " m_Num++;\n", " //最后将记录结果做返回\n", " return temp;\n", " }\n", "private:\n", " int m_Num;\n", "};\n", "\n", "//只能利用全局函数重载左移运算符\n", "ostream & operator<<(ostream &cout, MyInteger myint) //本质 operator << (cout , p) , 简化 cout << p\n", " //cout是别名,这里可以取out、kn...\n", " //cout为ostream输出流数据类型 \n", "{\n", " cout << myint.m_Num;\n", "\n", " return cout;\n", "}\n", "\n", "void test01()\n", "{\n", " MyInteger myint;\n", "\n", " cout << ++(++myint) << endl;\n", " cout << myint << endl;\n", "}\n", "\n", "void test02()\n", "{\n", " MyInteger myint;\n", "\n", " cout << myint++ << endl;\n", " cout << myint << endl;\n", "\n", "}\n", "\n", "int main()\n", "{\n", " test01();\n", " test02();\n", "\n", " /*\n", " int a = 0;\n", " cout << ++(++a) << endl; //运行结果为2\n", " cout << a << endl; //运行结果为2,表示一直对一个数据进行递增\n", " */\n", "\n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - 2 \n", " - 2 \n", " - 0 \n", " - 1 \n", " - 请按任意键继续. . ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 5. 赋值运算符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① C++编译器至少给一个类添加4个函数:\n", "\n", "1. 默认构造函数(无参,函数体为空)\n", "2. 默认析构函数(无参,函数体为空)\n", "3. 默认拷贝构造函数,对属性进行值拷贝\n", "4. 赋值运算符operator=,对属性进行值拷贝\n", "5. 如果类中有属性指向堆区,做赋值操作时也会出现浅拷贝问题。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "\n", "//重载赋值运算符\n", "\n", "class Person\n", "{\n", "public:\n", " Person(int age)\n", " {\n", " m_Age = new int(age);\n", " }\n", " \n", " ~Person()\n", " {\n", " if (m_Age != NULL)\n", " {\n", " delete m_Age;\n", " m_Age = NULL;\n", " }\n", " }\n", "\n", " //重载 赋值运算符\n", " //如果返回的是值,而不是引用,是创建一个拷贝函数,返回的是一个副本,而不是自身\n", " Person& operator=(Person& p)\n", " {\n", " //编译器默认是提供浅拷贝\n", " //m_Age = p.m_Age;\n", "\n", " //浅拷贝带来的问题是,当创建数据在堆区时,析构代码导致内存重复释放,报错\n", "\n", " //应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝\n", " if (m_Age != NULL)\n", " {\n", " delete m_Age;\n", " m_Age = NULL;\n", " }\n", "\n", " //深拷贝\n", " m_Age = new int(*p.m_Age);\n", "\n", " //返回对象本身\n", " return *this;\n", " }\n", "\n", " int *m_Age;\n", "};\n", "\n", "void test01()\n", "{\n", " Person p1(18);\n", "\n", " Person p2(20);\n", "\n", " Person p3(23);\n", "\n", " p3 = p2 = p1; //赋值操作\n", "\n", " cout << \"p1的年龄为:\" << *p1.m_Age << endl;\n", "\n", " cout << \"p2的年龄为:\" << *p2.m_Age << endl;\n", "\n", " cout << \"p3的年龄为:\" << *p3.m_Age << endl;\n", "\n", "\n", "}\n", "\n", "int main()\n", "{\n", " test01();\n", "\n", " /*\n", " \n", " int a = 10;\n", " int b = 20;\n", " int c = 30;\n", " \n", " c = b = a;\n", "\n", " cout << \"a= \" << a << endl;\n", " cout << \"b= \" << b << endl;\n", " cout << \"c= \" << c << endl;\n", " */\n", "\n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - p1的年龄为:18 \n", " - p2的年龄为:18 \n", " - p3的年龄为:18 \n", " - 请按任意键继续. . ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 6. 关系重载运算符" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "#include\n", "\n", "//重载关系运算符\n", "\n", "class Person\n", "{\n", "public:\n", " Person(string name, int age)\n", " {\n", " m_Name = name;\n", " m_Age = age;\n", " }\n", "\n", " //重载 == 号\n", " bool operator==(Person& p)\n", " {\n", " if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)\n", " {\n", " return true;\n", " }\n", " return false;\n", " }\n", "\n", " bool operator!=(Person& p)\n", " {\n", " if (this->m_Name != p.m_Name && this->m_Age != p.m_Age)\n", " {\n", " return true;\n", " }\n", " return false;\n", " }\n", "\n", " string m_Name;\n", " int m_Age;\n", "};\n", "\n", "void test01()\n", "{\n", " Person p1(\"Tom\", 17);\n", "\n", " Person p2(\"Jerry\", 18);\n", "\n", " if (p1 == p2)\n", " {\n", " cout << \"p1和p2是相等的!\" << endl;\n", " }\n", " else\n", " {\n", " cout << \"p1和p2是不相等的!\" << endl;\n", "\n", " }\n", "\n", " if (p1 != p2)\n", " {\n", " cout << \"p1和p2是不相等的!\" << endl;\n", " }\n", " else\n", " {\n", " cout << \"p1和p2是相等的!\" << endl;\n", "\n", " }\n", "\n", "\n", "}\n", "\n", "int main()\n", "{\n", " test01();\n", " \n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - p1和p2是不相等的! \n", " - p1和p2是不相等的! \n", " - 请按任意键继续. . ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 7. 函数调用运算符重载" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "① 函数调用运算符()也可以重载。\n", "\n", "② 由于重载后使用的方式非常像函数的调用,因此称为仿函数。\n", "\n", "③ 仿函数没有固定写法,非常灵活。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "using namespace std;\n", "#include\n", "\n", "//函数调用运算符重载\n", "\n", "//打印输出类\n", "class MyPrint\n", "{\n", "public:\n", "\n", " //重载函数调用运算符\n", " void operator()(string test)\n", " {\n", " cout << test << endl;\n", " }\n", "\n", "};\n", "\n", "//正常函数\n", "void MyPrint02(string test)\n", "{\n", " cout << test << endl;\n", "}\n", "\n", "void test01()\n", "{\n", " MyPrint myPrint;\n", "\n", " myPrint(\"hello world\");\n", "\n", "}\n", "\n", "//仿函数非常灵活,没有固定的写法\n", "//加法类\n", "class MyAdd\n", "{\n", "public:\n", " int operator()(int num1, int num2)\n", " {\n", " return num1 + num2;\n", " }\n", "};\n", "\n", "void test02()\n", "{\n", " MyAdd myadd;\n", " int ret = myadd(100,100);\n", " cout << \"ret = \" << ret << endl;\n", "\n", " //匿名函数对象\n", " cout << MyAdd()(100, 100) << endl;\n", "\n", " // MyAdd()为创建一个匿名对象,匿名对象的特点为当前行执行完立即释放\n", "}\n", "\n", "int main()\n", "{\n", " test01();\n", "\n", " MyPrint02(\"hello world\"); //由于使用起来非常类似于函数调用,因此称为仿函数\n", "\n", " test02();\n", "\n", " system(\"pause\");\n", "\n", " return 0;\n", "\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "运行结果: \n", " - hello world \n", " - hello world \n", " - ret = 200 \n", " - 200 \n", " - 请按任意键继续. . ." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.6.3", "language": "python", "name": "python3.6.3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.3" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 4 }