一,运算符重载的基础知识
1.什么是运算符重载
所谓的重载,就是重新赋予新的含义。函数的重载是让一个已经存在的函数赋予一个新的含义,使之实现新的功能。因此,一个函数名就可以用来代表不同功能的函数。运算符的重载其实我们已经使用过了,例如常见的"+"加法操作就是C++默认重载的,我们可以用加法对整数,单精度,双精度的数据进行加法运算,也是一个运算符可以有不同的功能。C++还为我们提供了自己进行运算符重载的方式。
2.运算符重载的推演
我们可以自然而然的使用“+”号对两个整数或者浮点数进行求和运算,但是如果是复数呢,我们就不能简单的用“+”号来进行操作,就必须要用函数来进行两个复数的操作,下面来进行运算符重载的推演。
3.运算符重载推演代码的实现
# include<iostream> using namespace std; /* 定义复数类 */ class Complex { private: int a; int b; friend Complex& operator+(Complex& c1, Complex& c2); public: Complex(int a, int b) { this->a = a; this->b = b; } int getA() { return this->a; } int getB() { return this->b; } void print() { cout << a << " + " << b << "i" << endl; } }; /* 两个复数相加的函数 */ void add(Complex& c1, Complex& c2) { Complex tmp(c1.getA() + c2.getA(), c1.getB() + c2.getB()); tmp.print(); } /* 定义operator+函数 */ Complex& operator+(Complex& c1, Complex& c2) { Complex tmp(c1.a + c2.a, c1.b + c2.b); return tmp; } int main() { Complex c1(1, 2); Complex c2(3, 4); /* 普通全局函数的两个复数相加 */ add(c1, c2); /* operator+友元函数的两个复数相加 */ Complex c3 = operator+(c1, c2); c3.print(); /* 这时,我们替换operator+函数名称为+号,此时就是操作符的重载 */ Complex c4 = c1 + c2; c4.print(); return 0; }
4.运算符重载的推演总结
- 所谓的操作符重载,其本质还是函数,只是函数的名称换成了我们常见的操作符而已
- 由于我们的类常常将类的属性设为私有,所以此时的操作符重载函数是友元函数,就可以快捷访问私有属性。
二,操作符重载编程基础
1.操作符重载的两种方法
- 操作符重载的本质函数为成员函数或者友元函数。
- 关键区别在于成员函数有this指针,友元函数没有this指针。
- 不管是友元函数重载还是成员函数重载,运算符的使用方法相同。但传递参数的方式不同,实现代码不同,应用的场合也不同。
2.二元运算符的重载
- 所谓的二元运算符是指操作符对两个对象进行操作。例如常见的加法就是二元操作符,对两个数进行相加。
- 二元运算符本质函数为成员函数,则成员函数参数只有一个,为操作符右边的数据,操作符左边的数据就是this指针对象。
- 二元运算符本质函数为友元函数,则操作符的左右两边数据都由友元函数的参数来进行传递接收。
3.二元运算符两种重载方式的实现
# include<iostream> using namespace std; /* 定义复数类 */ class Complex { private: int a; int b; public: /* 友元函数方式实现操作符(+)重载 */ friend Complex& operator+(Complex& c1, Complex c2); public: Complex(int a, int b) { this->a = a; this->b = b; } /* 成员函数方式实现操作符(-)重载 */ Complex& operator-(Complex& c) { Complex tmp(this->a - c.a, this->b - c.b); return tmp; } void print() { cout << a << " + " << b + "i" << endl; } }; /* 友元函数实现操作符重载的函数实现 */ Complex& operator+(Complex& c1, Complex c2) { Complex tmp(c1.a + c2.a, c1.b + c2.b); return tmp; } int main() { /* 定义两个复数 */ Complex c1(1, 2), c2(3, 4); /* 测试操作符+,用友元函数实现 */ Complex c3 = c2 - c1; c3.print(); /* 测试操作符-,用成员函数实现 */ Complex c4 = c1 + c2; c4.print(); return 0; }
4.一元操作符的重载
- 所谓的一元操作符就是操作只有一个要操作的数据,例如常见的自加加和自减减。
- 一元操作符分为前置方式和后置方式,例如a++和++a。C++通过一个占位参数来区分前置运算和后置运算。
- 前置方式我们按照正常思路书写即可,分为成员函数和友元函数两个方式实现。
- 后置方式我们需要进行操作符重载函数的重载,我们需要用占位符来实现重载。
5.一元操作符重载的代码实现
# include<iostream> using namespace std; class Complex { private: int a; int b; public: /* 友元函数实现前置++运算符的重载 */ friend Complex& operator++(Complex& c); /* 友元函数实现后置++运算符的重载 */ friend Complex& operator++(Complex& c, int); public: Complex(int a, int b) { this->a = a; this->b = b; } /* 成员函数实现前置--运算符的重载 */ Complex& operator--() { --this->a; --this->b; return *this; } /* 成员函数实现后置--运算符的重载 */ Complex& operator--(int) { /* 返回临时的this对象后,再进行this属性的减一运算 */ Complex tmp(this->a, this->b); --this->a; --this->b; return tmp; } void print() { cout << a << " + " << b << "i" << endl; } }; /* 友元函数实现前置++运算符的重载 */ Complex& operator++(Complex& c) { ++c.a; ++c.b; return c; } /* 友元函数实现后置++运算符的重载 */ Complex& operator++(Complex& c,int) { Complex tmp(c.a, c.b); ++c.a; ++c.b; return tmp; } int main() { /* 定义复数 */ Complex c1(1, 2); /* 前置++ */ ++c1; c1.print(); /* 前置-- */ --c1; c1.print(); /* 后置++ */ Complex c2 = c1++; c2.print(); c1.print(); /* 后置-- */ Complex c3 = c1--; c3.print(); c1.print(); return 0; }
6.运算符重载的实现步骤
- 首先必须承认操作符重载本质是一个函数,根据重载哪个操作符,书写哪个函数名称,例如:operator+()
- 第二需要确认函数的参数,也就是确认操作符是操作几个数据,如复数自减减,则是一个数据。然后再确定是用友元函数还是成员函数实现。
- 第三需要确认函数的返回值,也就是确认操作符运算后的结果是什么数据类型。
7.友元函数的使用场景
- 当要重载的操作符左边是无法修改的类(例如:ostream)则必须使用友元函数,而无法使用成员函数(因为成员函数的左侧只能是this,即类的本身)。
- =,[],(),和->操作符只能通过成员函数进行重载。
- 友元函数重载运算符通常用于操作符两侧类型不一致的情况。
8.友元函数实现<<和>>操作符的重载
# include<iostream> using namespace std; class Complex { private: int a; int b; public: /* 友元函数实现<<和>>操作符的重载 */ friend ostream& operator<<(ostream& out, Complex& c); friend istream& operator>>(istream& in, Complex& c); }; /* 友元函数实现<<和>>操作符的重载 */ ostream& operator<<(ostream& out, Complex& c) { out << c.a << " + " << c.b << "i"; /* 返回输出流对象,让其支持链式编程 */ return out; } istream& operator>>(istream& in, Complex& c) { in >> c.a >> c.b; return in; } int main() { /* 请输入一个复数 */ cout << "请输入一个复数(实部和虚部用空格分开):" << endl; /* 定义一个复数 */ Complex c; /* 接收输入的复数 */ cin >> c; /* 打印接收的复数 */ cout << c << endl; return 0; }
三,常见操作符的重载
1.重载赋值运算符=
# define _CRT_SECURE_NO_WARNINGS # include<iostream> using namespace std; class Name { private: char * name; public: /* 无参构造函数 */ Name() { this->name = NULL; cout << "无参构造函数执行..." << endl; } /* 有参构造函数 */ Name(char * name) { this->name = new char[strlen(name) + 1]; strcpy(this->name, name); cout << "有参构造函数执行..." << endl; } /* 拷贝构造函数 */ Name(const Name& n) { this->name = new char[strlen(n.name) + 1]; strcpy(this->name, n.name); cout << "拷贝构造函数执行..." << endl; } /* 析构函数 */ ~Name() { if (this->name != NULL) { delete[] this->name; this->name = NULL; } cout << "析构函数执行..." << endl; } public: /* 等号操作符重载 */ Name& operator=(Name& n) { cout << "等号操作符重载执行..." << endl; if (this->name != NULL) { delete[] this->name; this->name = NULL; } this->name = new char[strlen(n.name) + 1]; strcpy(this->name, n.name); return *this; } }; int main() { Name n1("王刚"); /* 拷贝构造执行 */ Name n2 = n1; /* 赋值运算符 */ Name n3; n3 = n2; return 0; }
2.重载数组下标运算符[]
# include<iostream> using namespace std; class Vector { private: int * ptr; int len; public: Vector(int len) { ptr = new int[len]; this->len = len; } ~Vector() { if (this->ptr != NULL) { delete[] this->ptr; this->ptr = NULL; } } public: /* 重载下标运算符 */ int& operator[](int& i) { return this->ptr[i]; } }; int main() { Vector v(10); /* 赋值 */ for (int i = 0; i < 10; i++) { v[i] = i; } /* 获取元素 */ for (int i = 0; i < 10; i++) { cout << v[i] << " "; } return 0; }
3.重载函数调用符()
# include<iostream> using namespace std; class String { private: char * ptr; public: /* 有参构造函数 */ String(char * ptr) { this->ptr = new char[strlen(ptr) + 1]; } /* 析构函数 */ ~String() { if (this->ptr != NULL) { delete[] this->ptr; this->ptr = NULL; } } public: /* 重载函数调用符() */ String& operator()(char * ptr) { if (this->ptr != NULL) { delete[] this->ptr; this->ptr = NULL; } this->ptr = new char[strlen(ptr) + 1]; strcpy(this->ptr, ptr); return *this; } /* 重载左移运算符 */ friend ostream& operator<<(ostream& out, String& s); }; /* 重载左移运算符 */ ostream& operator<<(ostream& out, String& s) { out << s.ptr; return out; } int main() { /* 调用有参构造函数 */ String str("王刚"); /* 调用重载操作符(),将王刚修改为张文婧 */ str("张文婧"); /* 打印str */ cout << str << endl; }