C++运算符重载的实现

来源:互联网 发布:机甲世纪革新版数据 编辑:程序博客网 时间:2024/06/05 09:28

   说起CPP的运算符重载,总是让人有些不理解,如果这是函数这个函数长得也太怪了吧,YES ,就是一种函数,只是这种函数时我们在给CPP所给的运算符功能上面添加功能时候使用的一种函数,注意不能减少CPP已经存在的的运算符的功能。

     定义一个重载运算符就像定义一个函数,只是该函数的名字是operator@,这里@代表运算符。函数参数表中参数的个数取决于两个因素:

1) 运算符是一元的(一个参数)还是二元的(两个参数)。

2) 运算符被定义为全局函数(友员函数,普通函数)(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数 — 对象变为左侧参数)。

     因为我们一般运算符重载都是为了数据的访问,如果数据属于公有的,那么就可以将运算符重载为普通函数,一般作为CPP的封装性质,一般就将运算符重载为成员函数和友员函数。那么问题来了,到底什么时候重载为友员函数,什么时候重载为成员函数

  在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。而在某种情况下,程序员没得选择,只能重载为类成员。

但成员函数运算符与友元函数运算符也具有各自的一些特点:

 (1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。

(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。必须将他们定义为成员,定义为非成员函数将在编译的时候出现错误。

(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。

(4) 若一个运算符的操作需要修改对象的状态或者与给定类型紧密联系的一些操作符,选择重载为成员函数较好。如自增,自减,解引用。

(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。

(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现(插入,提取 运算符的重载)。

(7) 当需要重载运算符具有可交换性时,即对称的操作符,如关系运算符,相等操作符,算数运算符,位操作符,则选择重载为友元函数。

虽然可以重载几乎所有 C中可用的运算符,但使用它们是相当受限制的(具体的限制参看这篇文章)。特别地,不能结合C中当前没有意义的运算符(例如 * *求幂),不能改变运算符的优先级,不能改变运算符的参数个数。这样限制有意义—所有这些行为产生的运算符只会造成意思混淆而不是使之清楚。


当然下面是所谓的“常用”的运算符的重载。他们的重载完全基于上边的这些规则,如果既可以重载为友员函数,也可以重载为成员函数,我会给出两种方式:

                                     以下是可以重载的运算符


双目算术运算符     + (加),-(减),*(乘),/(除),% (取模)
关系运算符     ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符     ||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符     + (正),-(负),*(指针),&(取地址)
自增自减运算符     ++(自增),--(自减)
位运算符     | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符     =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放     new, delete, new[ ] , delete[]
其他运算符     ()(函数调用),->(成员访问),->*(成员指针访问),,(逗号),[](下标)

不能重载的运算符只有5个:
.  (成员访问运算符)
.*  (成员指针访问运算符)
::  (域运算符)
sizeof  (长度运算符)
?:  (条件运算符)

前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和sizeof 运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征,C++不允许重载三目运算符。

运算符分为单目双目和三目:

运算所需变量为一个的运算符叫单目运算符,又叫一元运算符.
逻辑非运算符【!】、按位取反运算符【~】、自增自减运算符【++, --】、负号运算符【-】、类型转换运算符【(类型)】、指针运算符和取地址运算符【*和&】、长度运算符【sizeof】

运算所需变量为两个的运算符叫做双目运算符,例如+,-,*,/,%,<,>,>=,<=,==,!=,<<,>>,&,^,|,&&,||,=

运算所需变量为三个的运算符叫做三目运算符,只有条件表达式【?:】

/*/*********************************************************************** *   Copyright (c)2015,WK Studio* *   Filename:  String.h* *   Compiler: GCC  vs2013* *   Author:WK* *   Time: 2015 16 6* **********************************************************************/#include<iostream>#include<assert.h>using namespace std;class A{public:A(int i = 0):m_data(i){cout << "Create the Object! " << this << " \n";}A(const A &a);~A(){//free()对于含有指针数据的对象cout << "Destructor the Object!" << this << " \n";}A& operator=(const A &a);//可以返回引用也可以返回对象,返回引用更好偶//+ - * / %  (对象之间的操作都是对各自的数据进行操作)A operator+(const A &a);//返回对象足以实现连续的+friend A operator+(const A &a, const A &b);//+= -= *= /= %= A& operator+=(const A &a);//可以返回引用也可以返回对象,返回引用更好偶friend A operator+=(  A &a,const A &b);//单目运算符重载(正,负,解引用,取地址)//+号雷同A& operator - ();friend A operator -(A &a);//取地址&A* operator & ();//返回对象地址用对象指针接受//friend A * operator&(A &a);//解引用A& operator * ();friend A&  operator* (A &a);//条件运算符 == !=  < >  >=  <= 雷同bool operator == (const A &a);friend bool operator == (const A &a, const A &b);//逻辑运算符重载(&&  ||)bool operator &&(const A & a);friend bool operator && (const A &a, const A&b);bool operator !();friend bool operator !(A &a);//自增减运算符重载A& operator ++ ();//前置++//friend A& operator ++ (A &a);//前置++A operator ++ (int);//后置++//A& operator --();//前置--   雷同//A operator -- (int);//后置--//只能用友元函数重载friend inline ostream &operator << (ostream&, A&);//提取运算负的重载friend inline istream &operator >> (istream&, A&);//插入运算符的重载//位运算符重载A operator | (const A&);friend A operator | (const A &a, const A &b);//A operator & (const A&);//A operator ^ (const A&);A operator << (int i);friend A operator << (A &a,int i);//A operator >> (int i);A operator ~ ();friend A operator ~(A &a);int& operator () ();private:int m_data;};int main(){A s1(4);A s2(5);A s3 = s1 + s2;A s4;s4= s1 + s2 + s3;cout << s1() << "\n";s1() = 5;cout << s1() << "\n";A  s17 = s1.operator~();//s17 = ~s1;A s18 = operator~(s1);//调用友员函数A s15 = s1.operator<<(2);//s15= s1<<2;因为<<存在多个重载函数,无法鉴别,所以可以删除几个在使用A s16 = operator<<(s1, 2);//调用友员函数A s14= s1 | s2;A s12 = ++s1;s4 = s1.operator+(s2);s4 = operator+(s1, s2);A s6;//s6 += s1;//当+=的两个重载即成员函数重载和友员函数重载都在时候就会出现不知道调用那一个,用时候删掉一个s6.operator+=(s1);s6 = operator+=(s6, s1);A s5 = s1 = s2 = 999;//从右至左,先是用99生成一个临时对象,在调用两次赋值函数,在调用一次拷贝构造A s7(-1);A s8 = s7.operator-();//-s7;当-的两个重载即成员函数重载和友员函数重载都在时候就会出现不知道调用那一个,用时候删掉一个A s9=operator-(s7);operator-(s7);//友员函数调用//A *p = &s1;//当&的两个重载即成员函数重载和友员函数重载都在时候就会出现不知道调用那一个,用时候删掉一个A *p = s1.operator &();//A *p1 = operator&(s1);//友员函数调用A s10 = p->operator*();A s11 = operator*(s1);cout << (s10 == s11) << "\n";cout << (s10 && s11) << "\n";cout << s10.operator!() << "\n";cout << operator!(s10)<<"\n";A s13;cin >>s13;cout<<s13;getchar();return 0;}//拷贝构造(对于这种只有的整型的对象可以使用默认的拷贝构造,但是对于对象的数据是指针或者其他就要重新定义拷贝构造) A:: A(const A &a){ cout << "Copy the Object!  "<<this<<"  "<<&a<<" \n"; m_data = a.m_data;}A A:: operator+(const A &a){cout << "A:: + overloadFun the Object! " << this<<"  " << &a << " \n";return A(this->m_data+ a.m_data);}A operator+(const A &a, const A &b){cout << "Friend + overloadFun the Object!  "<<&a<<"  "<<&b<<" \n";return A(a.m_data + b.m_data);}A& A:: operator=(const A &a){cout << "(Only)A:: = overloadFun the Object! " << this << "  " << &a << " \n";if (this != &a){//free()对于数据是指针要先进行内存的释放this->m_data = a.m_data;}return *this;}A& A:: operator+=(const A &a){cout << "+= overloadFun the Object!  \n";this->m_data +=a.m_data;//*this +=a.data;引起不停的调用+=重载函数无限循环,vs中会将后边的数据生成一个临时对象进行相加,vc6.0会报错必须*this +=(A)a.data;*this= *this + a.data;也是对的                     return *this;}A operator+=(A &a, const A &b){cout << "Friend += overloadFun the Object!  \n";a.m_data +=b.m_data;return A(a.m_data);}A& A:: operator - (){cout << "- overloadFun the Object!  \n"; this->m_data= -this->m_data; return *this;}A operator -(A &a){cout << "Friend - overloadFun the Object!  \n";a.m_data = -a.m_data;return A(a.m_data);}A* A:: operator & (){cout << "& overloadFun the Object!  \n";return this;}/* A * operator&(A &a){cout << "& Friend  overloadFun the Object!  \n";return  &a;//成员函数与友员函数不能同时存在,否则这个&就会调用成员函数重载的&}*/A& A:: operator * (){cout << "* overloadFun the Object!  \n";return *this;}A&  operator * (A &a){cout << "*v Friend overloadFun the Object!  \n";return a;}bool A:: operator == (const A &a){cout << "== overloadFun the Object!  \n";if (this->m_data == a.m_data){return true;}return false;}bool operator == (const A &a,const A &b){cout << "== Friend overloadFun the Object!  \n";if (a.m_data == b.m_data){return true;}return false;}bool A:: operator && (const A &a){cout << "&& overloadFun the Object!  \n";if (this->m_data && a.m_data){return true;}return false;}bool operator &&(const A &a, const A & b){cout << "&& Friend overloadFun the Object!  \n";if (a.m_data && b.m_data){return true;}return false;}bool A:: operator !(){cout << "! overloadFun the Object!  \n";if (this->m_data == 0){return true;}return false;     }bool operator !(A &a){cout << "! Friend overloadFun the Object!  \n";if (a.m_data == 0){return true;}return false;}A& A::operator ++ (){++m_data;return *this;}/*A operator++ (A &a)//前置++{return A(++a.m_data);}*/A A::operator ++ (int)//后置++{return A(m_data++);}ostream &operator << (ostream &out, A &a)//提取运算负的重载{out << a.m_data;return out;}istream &operator >> (istream &in, A &a)//插入运算符的重载{int data;in >> data;a.m_data = data;return in;}A A::operator | (const A &a){return A(this->m_data | a.m_data);}A operator | (const A &a, const A &b){return A(a.m_data | b.m_data);}A A:: operator << (int i){return A(this->m_data << i);}A operator << (A &a, int i){return A(a.m_data<<i);}A A::operator ~ (){return A(~this->m_data);}A operator ~ (A &a){return A(~a.m_data);}int& A::operator () (){return this->m_data;}



//类型转换符重载

/**********************************************************************   * Copyright (c)2015,WK Studios * Filename:     * Compiler: GCC  VC6.0  win32   * Author:WK   * Time: 2015 6 6************************************************************************/#include<iostream>using namespace std;class S{public://类型转换符operator int(){return m_data;}//operator char* () const;    //operator const char() const;//operator short int() const;    //operator long long() const;S (int n):m_data(n){cout<<"Create the object!"<<this<<"\n";}~S(){cout<<"Free the object!"<<this<<"\n";} S operator =(S &a);S (S &a);private:int m_data;};int main(){S s1(5);int a=s1;return 0;}S S::operator =(S &a){if(this!=&a){m_data=a.m_data;}cout<<"= Operator  "<<this<<endl;return S(*this);}S::S(S &a){cout<<"Copy  "<<this<<endl;m_data=a.m_data;}
#include <iostream>using namespace std;//补充前置++和后置++的重载class A{private:   int m_data;public:A(int a=0):m_data(a){}A operator++(){return A(++m_data);}   A operator++(int)   {   return A(m_data++);   }  friend A operator++(A &a){return A(++a.m_data);} friend A operator++(A &a,int) {     return A(a.m_data++); } void show() { cout<<m_data<<"\n"; }};int main(){A a(1);    a.operator++(); //++a;前置++的成员函数调用a.show();a.operator++(0);//a++;后置++的成员函数调用a.show();operator++(a);//++a;前置++的友员函数调用a.show();operator++(a,0);//a++;后置++的int 只是用来标识与前置++的区别,int参数一般默认传递值0      a.show();}

#include <iostream>using namespace std;//增加()运算符的重载class Matrix{private:int *m;int row ,col;public:Matrix(int =0,int =0);int& operator()(int,int);};  int main()  {  Matrix aM(10,10);  cout<<aM(3,4)<<"\n";  aM(3,4)=35;  cout<<aM(3,4)<<"\n";return 0;  }  Matrix::Matrix(int row,int col )  {  this->row=row;  this->col=col;  m=new int [col*row];  for(int i=0;i<col*row;++i)  {  *(m+i)=i;  }  }  int& Matrix::operator()(int r,int c)  {  return(*(m+(r*col)+c));  }

#include <iostream>using namespace std;//实现给某一天加上天数,重载运算符+的应用class date{public:date(int y=1970,int m=1,int d=1):year(y),month(m),day(d){}void show(){cout<<year<<": "<<month<<": "<<day<<" \n";}date& operator+(int );protected:private:int year;int month;int day;};static days[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};int isleap(int y){if((y%4==0 && y%100!=0)  || (y%400==0))return 1; else return 0;}int main(){   date s1(2015,1,1);    s1.show();    date s2;   s2=s1+365;   s2.show();return 0;}date& date:: operator+(int n){   int leap=isleap(this->year);   n+=this->day;   while(n>days[leap][this->month-1])   {   n-=days[leap][this->month-1];   if(++this->month==13)   {        this->month=1;this->year++;leap=isleap(this->year);   }   }this->day=n;return *this;}

对于->*的重载和()的重载

class sim{public:int f(int i)const{return 1;}};int (sim::*fp)(int)const;void  main(){sim *s;sim s1;fp = sim::f;     //&sim::f;cout<<(s->*fp)(3)<<endl;//并没有调用->*的重载    cout<<(s.*fp)(3)<<endl;  }
#include <iostream>using namespace std;class Dog{public:int run(int i)const{cout<<"run\n";return i;}int eat(int i)const{cout<<"eat\n";return i;}int sleep(int i)const{cout<<"sleep\n";return i;}typedef int(Dog::*Fun) (int)const;//这里的函数函数返回值可以使用模板进行扩展通用class FunObje{public:FunObje(Dog* p,Fun pm):ptr(p),pmen(pm)  {   cout<<"FunObje()\n";  }int operator()(int i)const{cout<<"operator()\n";return (ptr->*pmen)(i);}private:Dog *ptr;Fun pmen;};FunObje operator->*(Fun pmf)//返回一个无名临时对象{cout<<"operator->*()\n";return FunObje(this,pmf);}};void main(){Dog w;Dog::Fun pmf = Dog::run;           // &Dog::run;cout<<(w->*pmf)(1)<<endl;//调用->*的重载pmf = Dog::sleep;cout<<(w->*pmf)(2)<<endl;    pmf = Dog::eat;cout<<(w->*pmf)(3)<<endl;}











1 0
原创粉丝点击