运算符重载实质是函数的重载,所以我们先来了解一下重载函数。
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数名完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。
输出:
int: 1 float: 1.1运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
又是那句话:运算符重载实质是函数的重载
输出:
2此处一元运算符指的是 `++ -- ? ! & -(负号)等
分为前置和后置方式,需要引入一个无用的参数作为区别。作为前置可以返回引用,作为后置只能返回临时对象(然后再自增或者自减)。
const X& operator ++ ();//前置 const X operator ++ (int);//后置 const X& operator -- (); const X operator -- (int);自加函数友元方式 由于后置返回的是一个临时对象,所以需要一个新建的对象存起来,就有必要定义一个拷贝构造函数。
其他一元运算符基本上没有什么特别的。大家自己体会,如果想不明白请留言。
每当一个类中含有指针成员的时候要特别注意。如果使用已经创建的对象进行初始化时会自动调用拷贝构造函数,如果两个对象都已经初始化好了,要用=符号进行对象间的拷贝就会出问题。什么问题呢? 上代码:
#include <cstring> #include <iostream> using namespace std; class MyString { public: MyString(const char* str){count = strlen(str);pstr = new char[count+1];strcpy(pstr, str);} ~MyString(){delete []pstr;} void display(void){cout<<pstr<<endl;} private: char *pstr; int count; }; int main(void) { MyString s1("Hello");s1.display(); MyString s2("World");s2.display(); s2 = s1;//glibc detected : double free or corruption s2.display(); return 0; } /** valgrind内存泄露工具检测结果 Invalid free() / delete / delete[] / realloc() LEAK SUMMARY: definitely lost: 6 bytes in 1 blocks **/ 解释:使用valgrind内存泄露检测工具检测以后发现,出现了二次释放的问题,这个问题出在代码20行,在这个位置s1指针的值被赋给了s2,但是s2原来申请的堆空间没有被释放,s1和s2指向同一块堆空间,程序结束的时候s1与s2的析构函数被调用,于是就double free了。如何解决这个问题?答案就是重载=,当对象使用=赋值处理指针的时候释放原有的堆空间,新申请一段等长的堆空间进行拷贝,而不是两者指向同一个空间,不同的堆空间仅仅是内容一样就不会double free。
//核心代码 重载 '=' 号运算符 MyString& operator=(MyString& ref) { if (this != &ref) { delete []pstr;//删除自己申请的空间 count = ref.count; pstr = new char[count+1];//申请等长的新空间 strcpy(pstr, ref.pstr);//拷贝内存 } return (*this); }[]符号原规则是用来当作数组运算符,所以只允许有一个参数,不得没有参数,或者有多个参数,允许用户自定义功能。
#include <iostream> using namespace std; class MyArrary { public: MyArrary(int a1,int a2,int a3, int a4){arr[0]=a1;arr[1]=a2;arr[2]=a3;arr[3]=a4;} //operator overload : [] int& operator[](int num)//返回引用才能进行赋值操作 { if ((num < 0) || (num > 4)) { cout <<"error:"; num = 0; } return arr[num]; } private: int arr[4]; }; int main(void) { MyArrary ma(1,2,3,4); cout << ma[0]<<endl; //取值 ma[0] = 5; //赋值 cout << ma[5]<<endl; return 0; }输出:
TODO[]可以做左值又可以做右值,所以返回为引用,便于赋值。
括号通常用来访问多维数组,也可以自定义作用。同()一样可以做左值又可以做右值,所以返回引用。没有参数个数限制,允许没有参数。
#include <iostream> using namespace std; class DArrary { public: DArrary(int num){int i = 0; for (i = 0; i< 9;i++) arr[i/3][i%3] = num++;} void display(void){int i = 0;for (i = 0; i< 9;i++) cout<<arr[i/3][i%3]<<" ";cout<<endl;} //operator overload : () Multiple Parameters int& operator()(int a, int b) { return arr[a][b]; } //operator overload : () Singal Parameter int& operator()(int a) { return arr[a/3][a%3]; } //operator overload : () None Parameter int& operator()(void) { return arr[0][0]; } private: int arr[3][3]; }; int main(void) { DArrary arr(1);arr.display(); cout << arr(0,0) << endl; //取值 cout << arr(2,2) << endl; //取值 arr(0,0) = 11; //赋值 arr(2,2) = 22; //赋值 cout << arr(0,0) << endl; cout << arr(2,2) << endl; cout << arr(7) << endl; //取值 arr(7) = 33; //赋值 cout << arr(7) << endl; cout << arr() << endl; arr() = 111; arr.display(); return 0; }注意!特殊符号只能重载为非静态的成员函数,不能是友元函数和普通函数
友元函数形式的重载运算符由于友元的特性,没有this指针,所以只要多一个参数就好了。 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
自加友元 返回
friend const CounterB operator++(CounterB& ref, int dump);//后置自加重载运算符请尽可能的同原来的含义相同或相近,符合软件工程可理解性、可维护性的要求
百度百科之重载函数 百度百科之运算符重载 c++运算符重载总结_Wuyuan’s Blog C++运算符重载——重载特殊运算符 C++运算符重载——重载一元运算符