运算符重载

编程爱好者联盟 2016-09-30

不是所有的运算符都能重载, 以下的都不行 :: 作用域运算符号 . 成员访问运算符 .* 成员指针解引用 sizeof 求类型或者对象大小的运算符 ?: 三目运算符 typei类型信息运算符 写重载时注意:

  • 不要发明运算符重载,只能对已经有的运算符重载,不能发明运算符
  • 不能对基本类型的运算符的进行重载=>运算符重载中至少有一个类型是类类型
  • 不能改变运算符的运算特性和优先级,比如把二元运算符改成一元的
  • 只能重载成成员的运算符:=,+= ,-=, *=, /=, %=,[] 下标取值,() 圆括号运算符,-> 指针运算符,* 指针解引用运算符
  • 只能重载成全局函数的运算符:>>, <<
  • 如果不给一个类型提供赋值运算符,则编译器会体统一个默认的赋值运算符,这个运算符完成的是逐字节拷贝,这样会产生多个指针指向同一块内存,并且可能产生内存泄露。类似缺省的拷贝构造

+,*,*=重载

clasFraction{
    inx;
    iny;
    public:
        Fraction(inx=int y=1):x(x),y(y){}
        voishow(){
            cout<<x<<&#39;/&#39;<<y<<endl;
        }
        //成员形式的运算符重载,this充当第一个参数,且可以省略
        Fractiooperator+(const Fraction& fb)const{  //有这个的话不能和全局的区分,只留一个就行,
            returFraction(x*fb.y+y*fb.x,y*fb.y);
        }
        Fractiooperator*(const Fraction& fb)const{
            returFraction(x*fb.x,y*fb.y);
        }
        Fractiooperator*=(const Fraction& fb){      //当前对象要变,不能加const
            x*=fb.x;
            y*=fb.y;
            retur*this;
        }
};
//全局形式
Fractiooperator+(const Fraction& fa,const Fraction& fb){
    returFraction(fa.x*fb.y+fa.y*fb.x,fa.y*fb.y);
}

clasInteger{
    indata;
    public:
        Integer(indata=:data(data){ //后半部分才是真正的构造
        }
        voishow(){
            cout<<data<<endl;
        }
        /*
        //使用成员函数实现operator+
        Integeoperator+(const Integer& i)const{
        //  returInteger(data+i.data);  //匿名对象
            returdata+i.data;           //单参构造
        }
        */
        stativoid showData(Integer* mythis){        //static函数使用普通变量要this
            cout<<mythis->data<<endl;
        }
    private:
        //声明友元
        frienconst Integer operator+(const Integer& ia,const Integer& ib);
};
//使用全局函数实现operator+
consInteger operator+(const Integer& ia,const Integer& ib){
    //正常情况下权限有问题,可以定义一个getData()函数或用友元解决
    //开头的const是为了保证返回的临时结果不可以被覆盖
    returInteger(ia.data+ib.data);  
}

cout/cin重载

cout是ostream& 流类型不能复制,必须用引用类型,也不能const修饰,cin同理,编译器会先去ostream类型(L对象)中找一个成员函数operator<<(const Integer&),如果找不到就去全局找一个全局函数operator<<(ostream& ps,const Interger& i)

#include<iostream>
usinnamespace std;
clasInteger{
    indata;
    public:
        Integer(indata=:data(data){     //后半部分的初始化列表的部分才是真正的构造
        }
        frienostream& operator<<(ostream& os,const Integer& i);
        frienistream& operator>>(istream& is,Integer& i);
        //成员形式的operator==
        boooperator==(const Integer& i){
            returdata==i.data;  //返回指针的话this==&i(极少用)
        }
};
//全局形式的输出运算符重载
ostreamoperator<<(ostream& os,const Integer& i){
    returos<<i.data;
}
//全局形式的输入运算符重载
istreamoperator>>(istream& is,Integer& i){
    returis>>i.data;
}
inmain(){
    Integeia(,ib(0);
    if(ia==ib){
        cin>>ia;
        cout<<ia<<endl;
    }
    retur
}

二元运算符L#R的重载中编译器会先去L对象对应的类型中找一个重载函数叫operator#(R),没有就去全局函数中找一个全局函数叫operator#(L,R),最后综合选择最优调用

一元运算符重载

先去O对象对应的类型找一个成员函数叫operator#(), 如果找不到就去全局找一个全局函数operator#(O),#默认操作符号在前,操作数在后

clasInteger{
    indata;
    public:
        Integer(indata=:data(data){ //后半部分才是真正的构造
        }
        frienostream& operator<<(ostream& os,const Integer& i);
        frienistream& operator>>(istream& is,Integer& i);
        boooperator!(){
            retur!data;
        }
        Integeoperator-(){
            retur-data;
        }
        Integeroperator--(){        //前--
            data--;
            retur*this;
        }
        consInteger operator--(int){    //后--
            /*
            Integetmp=*this;
            data--;
            returtmp;
            */
            returdata--;    //返回的是变化之前的结果
        }
        Integeroperator++(){        //前++
            data++;
            retur*this;
        }
        consInteger operator++(int){    //后++
            returdata++;
        }
};
//全局形式的输出运算符重载
ostreamoperator<<(ostream& os,const Integer& i){
    returos<<i.data;
}
//全局形式的输入运算符重载
istreamoperator>>(istream& is,Integer& i){
    returis>>i.data;
}
inmain(){
    Integeia(,ib();
    cout<<!ia<<endl;
    cout<<!ib<<endl;
    cout<<-ia<<endl;
    cout<<-ia<<endl;        //注意是两个-,不是--
    cout<<-(-ia)<<endl;
    cout<<--ia<<endl;
    cout<<ia--<<endl;
    cout<<ia<<endl;
    cout<<++ia<<endl;
    cout<<ia++<<endl;
    cout<<ia<<endl;
    cout<<-ib<<endl;
}

new/delete运算符重载

clasA{
    inx;
    iny;
    public:
        A(){cout<<"A()"<<endl;}
        ~A(){cout<<"~A()"<<endl;}
};
stativoid* operator new(size_t size){   //new运算符全局的成员的都一个样
    cout<<"size="<<size<<endl;
    returmalloc(size);
}
stativoid operator delete(void* ptr){
    cout<<"ptr="<<ptr<<endl;
}
inmain(){
    Apa=new A();
    deletpa;
    retur
}
strin对象的使用:
inmain(){
    strinstra("hello");
    strinstrb="hello";
    strb="world";
    if(stra==strb)
        cout<<"stra==strb"<<endl;
    else
        cout<<"stra!=strb"<<endl;
    cout<<strb<<endl;
    cout<<(strb.append(test"))<<endl;
    cout<<(stra+=test")<<endl;
    cout<<(stra=stra+strb)<<endl;
    cout<<stra.size()<<endl;
    cout<<stra[4]<<endl;
    cout<<stra.at(4)<<endl;
    //把C++ string 变成const char*
    const char* mystr=stra.c_str();
    cout<<mystr<<endl;
    cout<<strlen(mystr)<<endl;
}

()的重载

#include<iostream>
using namespace std;
class Product{
    //产品数量
    int pcount;
    //产品单价
    double price;
    public:
        Product(int pcount=0,double price=0.0):pcount(pcount),price(price){}
        //重载()运算符
        double operator()(int c,double p){
            return c*p;
        }
        double operator()(int c,double p,double pct){
            return c*p*pct;
        }
        //重载()运算符,把当前对象类型变成int
        //int operator() (){    //Wrong! 
        operator int(){ //
            return pcount;
        }
        //把当前对象类型转换成double
        operator double(){
            return price;
        }
};
int main(){
    Product iphone;
    double sumprice=iphone(9,.6);   //对象已经创建了,这里的()可不是初始化
    cout<<sumprice<<endl;
    cout<<iphone(9,.6,0.8)<<endl;
    Product iphone6s(99,.4);
    int c=(int)iphone6s;
    cout<<c<<endl;
    double p=(double)iphone6s;
    cout<<p<<endl;
    return 0;
}

例子

#include<iostream>
using namespace std;
class Array{
    //数组容量
    int len;
    //元素的个数
    int size;
    //真正存储数据的指针
    int* data;
    public:
        //构造
        expliciArray(int len=:len(len),size(0){ 
        //size一定要初始化为否则容易越界
            //申请堆内存
            data=neint[len];
        }
        //析构    
        ~Array(){
            //释放堆内存
            delete[data;
        }
        //拷贝构造
        Array(consArray& arr){
            //浅拷贝
            len=arr.len;
            size=arr.size;
            //深拷贝,重新申请堆内存
            data=neint[len];
            //复制数据
            for(ini=i<size;i++)
                data[i]=arr.data[i];
        }
        //添加数据
        voipush_back(int d){
            if(size>=len)
                expand();
            data[size++]=d;
        }
        //扩容
        voiexpand(){
            len=len+1;
            //记录原来的内存
            in*tmp=data;
            //重新申请堆内存
            data=neint[len];
            //复制数据
            for(ini=i<size;i++)
                data[i]=tmp[i];
            //释放原来的内存
            delete[tmp;
        }
        //显示数据
        //其实是全局函数写在了类内,输入输出重载不能在类内
        friend ostream& operator<<(ostream& os,const Array& arr){
            cout<<&#39;[&#39;;
            for(ini=i<arr.size;i++)
                cout<<arr.data[i]<<&#39; &#39;;
            cout<<"]";
        }
        //赋值运算符重载
        Arrayoperator=(const Array& arr){
            //防止自赋值
            if(this!=&arr){
                len=arr.len;
                size=arr.size;
                //释放原来的内存,防止原来的空间不够大
                delete[data;
                //重新申请内存
                data=neint[len];
                //复制数据
                for(ini=i<size;i++){
                    data[i]=arr.data[i];
                }
            }
            retur*this;
 
        }
        //[]运算符的重载
        intoperator[](const unsigned int i){//operator[]不能有默认值,因为有了默认值作为二元运算符的[]就变成了单目运算符
            retur*(data+i);
        }
 };
 voifoo(){
    Arraarra(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    arra.push_back(;
    Arraarrb;
    arrb=arra;
    cout<<arrb[<<endl;
    cout<<arrb<<endl;
 }
 inmain(){
    foo();
    retur
 }

相关推荐