C++运算符重载

C++运算符重载

文章目录

  • C++运算符重载
    • 1. 基本概念
    • 2. 重载运算符该不该作为成员函数
    • 3. 有哪些运算符支持重载?
      • 3.1 支持重载的运算符
      • 3.2 不支持重载的运算符
    • 4. 运算符重载实例
      • 4.1 C++ 输入/输出运算符重载
      • 4.2 ++和--
      • 4.3 下标运算符 [] 重载

参考 https://blog.csdn.net/lishuzhai/article/details/50781753
参考 https://blog.csdn.net/weixin_42837024/article/details/82496017
参考 https://wizardforcel.gitbooks.io/w3school-cpp/content/Text/66.html

1. 基本概念

为什么要对运算符进行重载 ?

C++ 预定义中的运算符的操作对象 只局限于基本的内置数据类型,但是对于我们自定义的类型(类)是没有办法操作的。但是大多时候我们需要对我们定义的类型进行类似的运算,这个时候就需要我们对运算符进行重新定义,赋予其新的功能,以满足自身的需求。

C++运算符重载的实质:

运算符重载的实质就是 函数重载或函数多态。运算符重载是一种形式的C++多态。目的在于让人能够用同名的函数来完成不同的基本操作。

运算符重载格式:
要重载运算符,需要使用被称为运算符函数的特殊函数形式。

<返回类型说明符> operator <运算符符号> ( <参数表> )
{
<函数体>
}

运算符重载的规则:

  • 为了防止用户对标准类型进行运算符重载,C++规定重载后的运算符的操作对象必须至少有一个是用户定义的类型。

也就是说不能对基本数据类型进行重载,这会破坏原有的运算规则。

  • 不能创建一个新的运算符,例如不能定义operator** (···)来表示求幂
  • 不能修改运算符原先的优先级。
  • 使用运算符不能违法运算符原来的句法规则。如不能将% 重载为一个操作数,

例如:
int index;
%index;这种是不被允许的。

  • 不能进行重载的运算符:成员运算符,作用域运算符,条件运算符,sizeof运算符,typeid(一个RTTI运算符),const_cast、dynamic_cast、reinterpret_cast、static_cast强制类型转换运算符。
  • 大多数运算符可以通过成员函数和非成员函数进行重载但是下面这四种运算符只能通过成员函数进行重载:

= 赋值运算符,
() 数调用运算符,
[ ] 下标运算符,
-> 通过指针访问类成员的运算符。

2. 重载运算符该不该作为成员函数

重载运算符有两种方式,即:

重载为类的成员函数 || 重载为类的非成员函数。

对于成员函数来说,一个操作数通过 this 指针隐式的传递,(即本身),另一个操作数作为函数的参数显示的传递;对于友元函数(非成员函数)两个操作数都是通过参数来传递的。

两者有何区别 ? 先上一段代码:

include <iostream>
using namespace std;

class Test{
public:
	Test(int para_x = 0):m_x(para_x){}; //构造函数
	Test operator + (const Test & B) const
	{
		Test obj;
		obj = this->m_x + B.m_x;//this指针可以省略
		return obj;
	}
private:
	int m_x;
};

int main()
{
	Test A(5),C;
	C = A + 3;
	return 0;
}

代码非常简单且正常运行,却足以说明问题。

C = A + 5; 可以写作 C = A.(5);
由 A 来调用 operator + 函数,而 5 则被构造成一个 Test 对象,这个构造过程就是隐式转换。(我们看不见,但是编译器这样做)

如果代码中是 C = 5 + A; 那么编译是不通过的,因为 5 可没有所谓的成员函数。

假如你想让这条语句编译通过,该如何做?

将这条语句解释为 C = operator+(5, A);不再使用 this 指针。通过非成员函数来实现操作符重载。

Test operator + (const Test & A,const Test & B) const

还有一个问题,既然是非成员函数,那么是作为普通成员函数,还是应该写作友元函数

对于类的非成员函数,通常我们都将其声明为友元函数,因为大多数时候重载运算符要访问类的私有数据,

当然也可以设置为非友元非类的成员函数。但是非友元又不是类的成员函数是没有办法直接访问类的私有数据的,就得通过在此函数中调用类的公有函数来访问私有数据会降低性能。

成员函数与非成员函数最大的区别在于是否有 this 指针。

小结:

T1 = T2 + T3; 可以解释为T1 = T2.operator+(T3); //成员函数
也可以解释为T1 = operator+(T2,T3);//非成员函数

  • 一般来说,单目运算符重载为类的成员函数,双目运算符重载为类的友元函数
  • 如果运算符的第一操作数要求为隐式转换则必须为友元函数

3. 有哪些运算符支持重载?

3.1 支持重载的运算符

C++运算符重载_第1张图片

3.2 不支持重载的运算符

C++运算符重载_第2张图片

4. 运算符重载实例

4.1 C++ 输入/输出运算符重载

C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。
我们可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。

#include 
using namespace std;

class Distance
{
private:
	int feet;             // 0 到无穷
    int inches;           // 0 到 12
public:
      
    Distance(){feet = 0;inches = 0;}
      
	Distance(int f, int i){feet = f;inches = i;}

    friend ostream &operator<<( ostream &output, const Distance &D )
    { 
         output << "F : " << D.feet << " I : " << D.inches;
         return output;            
    }

    friend istream &operator>>( istream  &input, Distance &D )
    { 
         input >> D.feet >> D.inches;
         return input;            
    }
};
int main()
{
   Distance D1;
   cout << "Enter the value of object : " << endl;
   cin >> D1;
   cout << "First Distance : " << D1 << endl;
   return 0;
}

C++运算符重载_第3张图片

4.2 ++和–

ClassName operator++ () // 重载前缀递增运算符( ++ )
ClassName operator++( int ) // 重载后缀递增运算符( ++ )

类似地,也可以写出重载递减运算符( – )。

4.3 下标运算符 [] 重载

下标运算符重载看起啦有些奇怪,其实我们是经常使用的。

string str(“hello,world”);
cout << str[0] << endl;

#include 
using namespace std;
const int SIZE = 10;

class safearay
{
private:
    int arr[SIZE];
public:
    safearay() 
    {
        register int i;
        for(i = 0; i < SIZE; i++){arr[i] = i;}
    }
    int operator[](int i)
    {
        if( i > SIZE )
        {
            cout << "Index out of bounds" <<endl; 
            return -1;
        }
        return arr[i];
    }
};
int main()
{
   safearay A;

   cout << "Value of A[2] : " << A[2] <<endl;
   cout << "Value of A[5] : " << A[5]<<endl;
   cout << "Value of A[12] : " << A[12]<<endl;

   return 0;
}

C++运算符重载_第4张图片

你可能感兴趣的:(C++)