更多参考其他文档菜鸟文档、W3C、微软C++文档
运算符重载
- c++预定义的运算符不能满足全部的运算需求,比如:复数的加减运算
- 希望能有一种特殊的运算,可以使类、等复杂的数据也可以进行运算,易于理解
- 运算符重载,就是对已有的运算符赋予更多含义的运算,可以使不同类型或者复杂的数据也可以进行运算。(比如类之间的运算)
- 即,对于自定义的这个运算符,具有唯一性,表达的含义只能作用于对应的运算数据 。 类a + 类 b
- 实质 函数重载
- 可以重载为普通函数,也可以重载为成员函数
- 实现 把含运算符的表达式转换成对运算符函数的调用
- 重载运算符,多个重载运算符时,根据参数选择
目数:运算所需变量个数
返回值类型 operator 运算符(形参表) { .... }
class Complex { public: double real,imag; Complex(double r = 0.0,double i=0.0):real(r),imag(i){} Complex operator-(const Complex & c); };
Complex operator +(const Complex &a,const Complex & b) { return Complex(a.real + b.real,a.imag + b.imag); } Complex Complex::operator-(const Complex & c) { return Complex(real - c.real, imag - c.imag); }
int main() { Complex a(4,4),b(1,1),c; c = a + b; cout << c.real << ","<<c.imag <<endl; cout << (a-b).real <<","<<(a-b).imag << endl; return 0; }
|
赋值运算符的重载
-
用于类型不匹配数据之间的赋值
-
赋值运算符“ = ” 只能重载为成员函数
class String { private : char * str; public: String():str(new char[1]){str[0] = 0;} const char * c_str(){return str;}; String & operator = (const char *s); ~String(){delete[] str;} };
String & String::operator = (const char * s) { delete [] str; str = new char[strlen(s)+ 1]; strcpy(str , s); return * this; }
int main() { String s; s = "Good Luck,"; cout << s.c_str() << endl; s = "Shenzhou 8!"; cout << s.c_str() << endl; return 0; }
|
浅拷贝和深拷贝
class String { private: char * str; public: String(): str(new char[1]){str[0] = 0;} const char * c_str() { return str;}; String & operator = (const char * s){ delete [] str ; str = new char[strlen(s)+1]; strcpy(str,s); return * this; }; ~String(){delete[] str;} };
int main() { String S1,S2; S1 = "this"; S2 = "that"; S1 = S2; return 0; }
String & operator = (const String & s){ delete [] str; str = new char[strlen(s.str) + 1]; strcpy(str,s.str); return * this; }
String & operator = (const String & s){ if (this == & this) return * this; delete [] str; str = new char[strlen(s.str) + 1]; strcpy(str,s.str); return * this; }
|
对 operator = 返回值类型的讨论
对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性
a = b = c ,导致“ = ” 不能连等
(a = b) = c 时,a = b 返回的是a的引用
a.operator(b.operator=(c)); (a.operator=(b)).operator=(c);
String (String & s) { str = new char [strlen(s.str) + 1]; strcpy(str,s.str); }
|
运算符重载为友元函数
- 一般情况下,运算符重载为类的成员函数已经够用,但是有特殊的情况,还需使之重载为普通函数,还可以访问该类的私有成员 ,所以需要重载为友元函数
class Complex { double real,imag; public: Complex(double r,double i):real(r),imag(i){}; Complex operator(double r); friend Complex operator+(double r,const Complex & c); };
Complex Complex::operator+(double r) { return Complex(real + r, imag); }
Complex operator+(double r,const Complex & c) { return Complex(c.real + r,c.imag); }
|
数组和结构
可变长数据类的实现
需要实现的功能
int main { CArray a; for( int i=0;i<5;++i) a.push_back(i); CArray a2,a3; a2 = a; for(int i = 0; i<a.length();++i) cout<<a2[i]<<""; a2 = a3; for(int i = 0; i<a2.length();++i) cout <<a2[i]<<" "; cout<<endl; a[3] = 100; CArray a4(a); for(int i = 0; i<a4.length();++i) cout<<a4[i]<<""; return 0; }
|
实现
#include <iostream> #include <string.h>
using namespace std;
class CArray { int size; int *ptr;
public: CArray(int s = 0); CArray(CArray &a); ~CArray(); void push_back(int v); CArray &operator=(const CArray &a); int length() { return size; } int &CArray::operator[](int i) { return ptr[i]; } };
CArray::CArray(int s) : size(s) { if (s == 0) { ptr = NULL; } else { ptr = new int[s]; } }
CArray::CArray(CArray &a) { if (!a.ptr) { ptr = NULL; size = 0; } ptr = new int[a.size]; memcpy(ptr, a.ptr, sizeof(int) * size); size = a.size; }
CArray ::~CArray() { if (ptr) { delete[] ptr; } } CArray &CArray::operator=(const CArray &a) { if (ptr == a.ptr) { return *this; } if (a.ptr == NULL) { if (ptr) { delete[] ptr; } ptr = NULL; size = 0; return *this; } if (size < a.size) { if (ptr) delete[] ptr; ptr = new int[a.size]; } memcpy(ptr, a.ptr, sizeof(int) * size); size = a.size; return *this; }
void CArray ::push_back(int v) { if (ptr) { int *tmpPtr = new int[size + 1]; memcpy(tmpPtr, ptr, sizeof(int) * size); delete[] ptr; ptr = tmpPtr; } else { ptr = new int[1]; } ptr[size++] = v; }
|
流插入选算符和流提取运算符的重载
cout << cout 是 ostream类的对象 <<
|
有可能的做法
void ostream::operator << (int n) { return; } void ...仿照上面写char的
ostream & ostream::operator<<(int n) { return * this; } ostream & ostream::operator<<(const char *s) { return *this; }
cout.operator<<(5).operator<<("this");
class CStudent { public : int nAge; }; int main() { CStudent s; s.nAge = 5; cout << s<< "hello"; return 0; }
ostream & operator <<( ostream & o,const CStudent & s) { o <<s.nAge; return o; }
#include <iostream> #include <string> #include<cstdlib>
using namespace std;
class Complex { double real ,imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i){}; friend ostream &operator<<(ostream &os, const Complex &c); friend istream &operator>>(istream &is, Complex &c); };
ostream &operator<<(ostream &os, const Complex &c) { os << c.real << "+" << c.imag << "i"; return os; }
istream &operator>>(istream & is,Complex & c) { string s; is >> s; int pos = s.find("+", 0); string sTmp = s.substr(0, pos); c.real = atof(sTmp.c_str()); sTmp = s.substr(pos + 1, s.length() - pos - 2); c.imag = atof(sTmp.c_str()); return is; }
|
类型转换运算符的重载
#include<iostream>
using namespace std; class Complex { double real, imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i){}; operator double() { return real; } };
int main() { Complex c(1.2, 3.4); cout << (double)c << endl; double n = 2 + c; cout << n; }
|
自增自减运算符的重载
-
自增运算符++、自减运算符–有前置\后置之分,为了区分所重载的是前置运算符还是后置运算符
-
前置运算 符当作一元运算符重载
- 重载为成员函数:
- T & operator++();
- T & operator–();
- 重载为全局函数:
- T1 & operator ++(T2);
- T1 & operator–(T2);
-
后置运算 符当作二元运算符重载,多写一个没用的参数:
- 重载为成员函数:
- T & operator++(int );
- T & operator–( int );
- 重载为全局函数:
- T1 & operator ++(T2,int);
- T1 & operator–(T2,int);
在没有后置运算符重载而有牵制重载的情况下,在VS中,obj也调用前置重载,而dev则令obj编译出错
int main() { CDemo d(5); cout << (d++)<<","; cout << d << ","; cout << (++d)<< ","; cout << d <<endl; cout << (d--) << ","; cout << d << ","; cout << (--d) << ","; cout << d << endl; }
class CDemo{ private: int n; public: CDemo(int i =0):n(i){} CDemo & operator++(); CDemo operator++(int); operator int () {return n;} friend CDemo & operator--(CDemo &); friend CDemo operator--(CDemo &,int); };
CDemo & CDemo ::operator++() { ++ n; return * this; }
CDemo & CDemo ::operator++( int k) { CDemo tmp(*this); n++; return tmp; } CDemo & operator--(CDemo & d) { d.n --; return d; } CDemo operator--(CDemo & d,int) { CDemo tmp(d); d.n--; return tmp; }
|
运算符重载的注意事项
- c++不允许定义新的运算符
- 重载后运算符的含义应该符合日常习惯
- complex_a + complex_b
- word_a > word_b
- date_b =date_a +n
- 运算符重载不改变运算符的优先级;
- 以下运算符不能被重载:“.” “.* ” “ :: ” “ ? : ” sizeof;
- 重载运算符()、[]、-> 或者赋值运算符 = 时,运算符重载函数必须声明为类的成员函数。