夯实基础(7):运算符重载

126 阅读2分钟

今天早上学妹问我一道习题让我帮她看看:

class Array{
    int length;
    int *arr;
public:
    Array(int *a, int len);
    ~Array();
}
//main()
int a[]={1,2,3};
Array Arr1(&a[0],3);
Array Arr2 = -Arr1 + 6*Arr1;
cout<<Arr1<<Arr2;

我一看,就是运算符重载嘛。一通操作之后,虽然弄出来了(放在最后),但是发现有些概念很是模糊,比如参数个数怎么确定,什么时候返回引用等等。回过头来还是记录一下。

C++ Tutorials

类是C++中定义的新类型,不仅可以构造和赋值,还可以使用操作符,就像普通类型那样:int a,b;int c = a + b;。此处,使用加法运算符将两个int型变量相加,然后赋值给c。如果变为类类型,则需要重载相应的运算符。C++允许重载大多数运算符,列表如下:
和普通函数一样,重载的运算符函数也有返回值、函数参数等,但函数名为operator关键字加运算符,语法格式为:type operator sign(parameters){}。几乎所有运算符重载都可以以成员函数版本实现,但部分运算符应该使用非成员函数版本实现。 例如,流输出运算符(<<)常通常使用友元方式重载:friend ostream& operator << (ostream& os, Array& target);。之所以使用友元,其一是为了符合输出时常用的cout<<惯用形式,即流输出运算符左侧应该是ostream对象,故不能以成员函数方式进行重载,而是使用类外普通函数形式。二是在类外要访问到Array类的私有数据成员,所以使用友元函数。

结果和总结

class Array{
    int length;
    int *arr;
public:
    Array(int *a,int len){
        length = len;
        arr = new int[len];
        for(int i=0;i<length;++i){
            arr[i] = a[i];
        }
    }
    ~Array(){delete []arr;}
    Array() = default;
    
    //copy
    Array(const Array &a){
        length = a.length;
        arr = new int[length];
        for(int i=0;i<length;++i){
            arr[i]=a[i];
        }
    }
    //copy assign
    Array& operator = (const Array &a){
        if(this!=&a){
            if(length!=a.length){
                delete []arr;
                length = a.length;
                arr = new int[length];
            }
            for(int i=0;i<length;i++){
                arr[i]=a.arr[i];
            }
        }
        return *this;
    }
    //+
    Array operator + (const Array &a){
        Array tmp;
        tmp.length = a.length;
        tmp.arr = new int[tmp.length];
        for(int i=0;i<tmp.length;++i){
            tmp.arr[i]=arr[i]+a.arr[i];
        }
        return tmp;
    }
    //-
    Array operator - (){
        Array tmp;
        tmp.length = a.length;
        tmp.arr = new int[tmp.length];
        for(int i=0;i<tmp.length;++i){
            tmp.arr[i]=-arr[i];
        }
        return tmp; 
    }
    //*
    Array operator * (int factor){
        Array tmp;
        tmp.length = length;
        tmp.arr = new int[tmp.length];
        for(int i=0;i<tmp.length;++i){
            tmp.arr[i] = factor*arr[i];
        }
        return tmp; 
    }
    friend Array operator * (int factor,Array &a){
        Array tmp = a.operator*(factor);
        return tmp;
    }
    //<<
    friend ostream& operator << (ostream &os, const Array &a){
        for(int i=0;i<a.length;++i){
            os<<a.arr[i]<<" ";
        }
        os<<endl;
        return os;
    }  
}

可以发现,如果是以成员函数形式重载,则需要的参数个数会少一个,因此类隐藏了其成员函数中的第一个参数this。另外,为*运算符实现了两种版本的重载,是为了满足int*ArrayArray*int这两种形式的运算。
其实理解运算符重载很容易,只是因为类中有时候会涉及到静态数据、动态数据等,导致编写代码时需要特别注意一下。