C++笔记——运算符重载

1、运算符重载

  • 运算符重载,就是对已有的运算符(C++中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为
  • 运算符重载的目的是:扩展C++中提供的运算符的适用范围,使之能作用于对象
  • 同一个运算符,对不同类型的操作数,所发生的行为不同

2、运算符重载的形式

  • 运算符重载的实质是函数重载
  • 可以重载为普通函数,也可以重载为成员函数
  • 把含运算符的表达式转换成对运算符函数的调用
  • 把运算符的操作数转换成运算符函数的参数
  • 运算符被多次重载时,根据实参的类型决定调用哪个运算符函数

   返回值类型 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;                                        // 等价于c=operator+(a,b);
    cout << c.real << "," << c.imag << endl;
    cout << (a-b).real << "," << (a-b).imag << endl;  //a-b 等价于a.operator-(b)
    return 0;
}

3、赋值运算符“=”只能重载为成员函数

   对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性

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::~String( ) { delete [] str; }
};
String & String::operator = (const char * s){ // 重载“=”得 以使得 obj = “hello” 能够成立
    if( this == & s)        //存在s = s 情况
        return * this;
    str = new char[strlen(s)+1];
    strcpy( str, s);
    return * this;
}

4、运算符重载为友元函数

  • 一般情况下,将运算符重载为类的成员函数,是较好的选择。
  • 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元
class Complex{
        double real,imag;
    public:
        Complex( double r, double i):real(r),imag(i){ };
        Complex operator+( double r );
};
Complex Complex::operator+( double r ){ //能解释 c+5
    return Complex(real + r,imag);
}
经过上述重载后:
Complex c ;
c = c + 5;   有定义,相当于 c = c.operator +(5);
但是:
c = 5 + c;   编译出错
所以,为了使得上述的表达式能成立,需要将 + 重载为普通函数
但是普通函数又不能访问私有成员,所以,需要将运算符 + 重载为友元。
class Complex{
    //...
    friend Complex operator + (double r,const Complex & c);
};

5、流插入运算符和流提取运算符的重载

ostream & ostream::operator<<(int n/const char * s ){
    …… // 输出n 的代码
    return * this;
}
cout << 5 << “this”;
cout.operator<<(5).operator<<(“this”); //本质上的函数调用的形式

6、自增,自减运算符和类型强制转换运算符的重载

  自增运算符++、自减运算符--有前置/后置之分,为了区分所重载的是前置运算符还是后置运算符,C++规定:
(1)前置运算符作为一元运算符重载

  • 重载为成员函数:

           T & operator++();
           T & operator--();

  • 重载为全局函数:

           T1 & operator++(T2);
           T1 & operator—(T2);

(2)后置运算符作为二元运算符重载,多写一个没用的参数:

  • 重载为成员函数:

         T operator++(int);
         T operator--(int);

  • 重载为全局函数:

        T1 operator++(T2,int );
        T1 operator—( T2,int);

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;
}                         // ++s即为: s.operator++();
CDemo CDemo::operator++( int k ){         //后置 ++
    CDemo tmp(*this);     // 记录修改前的对象
    n ++;
    return tmp;           // 返回修改前的对象
}                         // s++即为: s.operator++(0);
CDemo & operator--(CDemo & d){            // 前置--
    d.n--;
    return d;
}                         //--s即为: operator--(s);
CDemo operator--(CDemo & d,int){          // 后置--
    CDemo tmp(d);
    d.n --;
    return tmp;
}                         //s--即为: operator--(s, 0);

(3)operator int ( ) { return n; }

  • int 作为一个类型强制转换运算符被重载
Demo s;
(int) s ; //等效于 s.int();
  • 类型强制转换运算符被重载时不能写返回值类型,实际上其返回值类型就是该类型强制转换运算符代表的类型

7、运算符重载的注意事项

  • C++不允许定义新的运算符 ;
  • 重载后运算符的含义应该符合日常习惯;
  • 运算符重载不改变运算符的优先级;
  • 以下运算符不能被重载:“.”、“.*”、“::”、“?:”、sizeof;
  • 重载运算符()、[]、->或者赋值运算符=时,运算符重载函数必须声明为类的成员函数。

猜你喜欢

转载自blog.csdn.net/wys7541/article/details/81480793
今日推荐