C++运算符重载总结(真的很详细了w(゚Д゚)w)

C++运算符重载总结(真的很详细了w(゚Д゚)w)

概述

运算符重载可以使得一些特殊类型参与运算,我是这样理解的。


使用友元形式的运算符重载

//一般形式
class x{
	friend 返回类型 operator 运算符(形参表);
};
返回类型 operator 运算符(形参表)
{}

双目运算符

所以加减乘除就可以这样来进行声明了

返回类型 operator +(-、*、/) (形参表);

单目运算符

- & ! ++(前),++(后)等。下面以++(后)来进行一个示例:

class code{
    int x, y;
};
code operator++(code& op, int)//第二个参数仅仅表示这个++是后缀加
{
    code tmp(op);
 	x++;
    y++;
    return tmp;//返回增加之前的状态,这样也对后加加有了进一步理解了。
}

总结:

  1. 运算符重载可以返回任何类型,甚至是void类型,但是通常都是返回和操作数相同的类型。

  2. 下面运算符只能使用成员函数运算符重载,不能使用友元函数来重载。

    运算符名称
    = 等号
    [] 下标运算符
    () 函数调用运算符
    -> 指针成员运算符
  3. 对于同一个运算符,可以写多个函数来进行重载。


使用成员运算符进行重载

//一般形式
class x{
    返回类型 operator 运算符(参数表);
}
返回类型 x::operator 运算符(参数表)
{
    具体实现
}

双目运算符重载

这里需要注意的是:参数表中的个数会少一个,因为左操作数是隐含在this中的。
但是类内的静态函数没有this指针。

例如:

class code{
    int x, y;
    public:
    	code(int a, int b):x(a), y(b){}
    	code operator+(code p){
            return code(x+p.x, y+p.y);
		}
};
code A(1, 2), B(3, 4);
code C=A+B;//这时C.x=4, C.y=6;

单目运算符重载

形式和上面差不多,这里不再赘述。


运算符重载需要注意的几个问题

  1. c++语言只能对已经有的c++运算符进行重载,不允许用户自己定义新的运算符。

  2. 绝大多数运算符都能重载,但是有例外,下面五个不能进行重载

    名称
    . 成员访问运算符
    .* 成员指针访问运算符
    :: 作用域运算符
    sizeof 长度运算符
    ?: 条件运算符
  3. 重载的功能应当和原有的功能类似

  4. 重载不能改变运算符的操作对象

  5. 重载不能改变运算符原有的优先级

  6. 重载不能改变运算符原有的结合特性

  7. 重载参数应该至少有一个是类对象,不能都是c++预定义的类型(要不然就没有意义了)

  8. 双目运算符一般两种重载形式都可以,但是有的时候只能用友元形式来进行重载。例如:

    AB::operator+(int x){
        return AB(a+x, b+x);
    }
    ob1=ob2+100; //这里这样调用是可以的,编译器理解为ob1=ob2.operator(100);
    //但是下面的情况就会出现问题
    ob1=100+ob2; //等价于ob1=100.operator(ob2);但是100不是一个对象
    

    如果我们定义下面两个友元函数就会很好的解决这个问题

    friend AB operator+(AB ob, int x);
    friend AB operator+(int x, AB ob);
    //这样ob1=100+ob2; ob1=ob2+100;都没有问题
    //这里我们也可以整合,使用类型转换函数,将int类型转换为对象类型,对象类型转换为int类型,不过真没啥意思
    

几个常见的运算符重载

等号“ = ”运算符重载,只能使用成员函数进行重载

这里我们重载=主要是进行深拷贝操作(当然这里也可以自己写一个拷贝构造函数来进行)。

在重载等号运算符重载时要注意自己等于自己的情况

mystring& mystring::operator=(mystring &s)
{
       if(this==&s)return *this;//防止出现s=s的赋值;
       if(p!=NULL)
           delete []p;
       p=new char[strlen(s.p)+1];
       strcpy(p, s.p);
       return *this;
   }

下标运算符重载[]

只能使用成员函数进行重载,要注意这是个双目运算符x[y],x是左操作符,y是右操作符**

返回类型 类名::operator[] (参数表){
    函数体
}
//有时返回类型可以使用引用类型,只要不是返回的变量不是在函数内声明的临时变量就可以
class AB{
    int num[10];
    int len;
    int& operator[](int);
}
int& AB::operator[](int b)
{
    if(b<0 || b>=10)
        return -1;
    else return num[b]; //这里num[b]不是一个临时变量,而是存在于对象中。
}

函数调用运算符重载()

只能使用成员函数进行重载

注意这里()看被作双目运算符的,x(y), x是左操作数,y是右操作数

//给出坐标,返回二维矩阵的某个元素的值.
class matrix{
    int *m;//用一维的数组来进行模拟
    int row, col; //行数,列数
}
int& matrix::operator()(int r, int c){
    return *(m+r*col+c);
}
m(3, 5)//这里解释为m.operator()(3, 5);

()运算符是唯一一个可带多个右操作数的运算符函数


输出运算符和输入运算符的重载

<<运算符的重载

定义原型:需要注意成员函数形式和友元函数形式的区别,他们调用方式不相同

//成员函数类型,注意如果使用下面的类型,那么调用的方式是:对象名<<cout;
ostream& operator<<(ostream& out){
    out<<x<<" "<<y<<endl;
    return out;
}
ob<<cout;//相当于ob.operator<<(cout);
//因为上面这种形式有点反直觉,所以很少用,所以大部分都是采用友元形式

//友元函数类型
friend ostream& operator<<(ostream& out, 自定义类名& 对象名){
    //out可以改为别的名
    out<<对象.x<<对象.y<<endl;
    return out;
}
cout<<ob; //使用这种形式来进行输出

对于<<的参数详解,《C++ Primer中文版:第五版》(494)页是这样解释的:

输出运算符的第一个形参是一个非常量的ostream对象的引用。之所以ostream是非常量是因为向流写入内容会改变其状态;而该形参是因为我们无法复制一个ostream对象。

第二个形参一般来说是一个常量的引用,该常量是我们想要打印的类类型。第二个形参是引用的原因是我们希望避免赋值实参;而之所以该形参可以是常量是因为(通常情况下)打印对象不会改变对象的内容。

为了与其他输出运算符保持一致,operator<<一般要返回它的ostream形参。

>>输入运算符重载

这里的基本规则和上面重载输出运算符差不多,需要多注意的是,输入过程中要考虑到输入可能失败的情况。

欢迎评论交流!
原文地址:https://www.cnblogs.com/alking1001/p/12003178.html