C++ 运算符重载

一、运算符重载的概念

首先,我们提出两个问题,第一:为什么会有运算符重载?第二:什么是运算符重载?

第一,所谓运算符,就是“+  - * / "等此类运算符,只能用于对基本类型的常量、变量进行运算,不能用于对象之间的运算。

而我们为了对象之间也可以用,两个对象可以进行+/-等其他运算操作,便产生了“运算符重载”。

第二,什么是“运算符重载”呢?

以运算符和特定的关键字作为某个函数的函数名,传递给函数的实参作为运算符的操作数,函数的返回值作为运算的结果。

二、运算符重载详解

运算符重载函数既可以是成员函数,也可以是非成员函数。

【注:C++规定,运算符“=” 只能重载为成员函数】

1.二元运算符

下面以重载(+)为例:

#include <iostream>
#include <cstring>
using namespace std;
class Int
{
public:
    int value;

    Int(int v = 0) : value(v)//有默认参构造函数
    {
        cout << "Create Int: " << value << " " << this << endl;
    } 

    ~Int() //析构函数
    {
        cout << "Destory Int: " << value << " " << this << endl;
    }

    Int(const Int& c) //拷贝构造函数
    {
        value = c.value;
        cout << "Copy Int:" << this << endl;
    }

//运算符重载
    //对象 + 对象 :a+b;
    Int operator + (const Int& c) const
    {
        return Int(this->value + c.value);
    }

    //对象 + 常量 :a+10;
    Int operator + (const int x) const
    {
        return Int(this->value + x);
    }
};
    //常量 + 对象 :10+a;
    Int operator +(const int x, const Int& c)
    {
        return Int(x + c.value);
    }

int main()
{
    Int a(10), b(15); 
    Int c;
    c = a + b;
    cout << "a+b= " << c.value << endl;  //25
    cout << "a+10= " << (a + 10).value << endl; //20
    cout << "5+a= " << (10+a).value << endl; //15
}

运行结果:

 由结果可以看到:调用了6次构造函数(结果中十六进制数为对象的地址)。

举例分析一下a+b的运行过程:

1.构造了对象a,并初始化为10;

2.构造了对象b,并初始化为15;

3.构造了对象c,未初始化,默认为0;

4.执行”c=a+b",调用了重载“+”成员函数(对象+对象),构造了一个临时的不具名对象去返回函数值,其值为25;

5.a+b的值已返回,析构临时对象;

6.打印。

重载"+"成员函数:成员函数参数比运算符目数少1。

a+b ->a.operator+(b)->operator(&a,b)

重载"+"非成员函数:非成员函数参数等于运算符目数。

5+a-> operator+(5,&a)

2.关系运算符

下面以重载(>)为例:

#include <iostream>
#include <cstring>
using namespace std;

class Int
{
public:
    int value;

    Int(int v = 0) : value(v)//有默认参构造函数
    {
        cout << "Create Int: " << value << " " << this << endl;
    }

    ~Int() //析构函数
    {
        cout << "Destory Int: " << value << " " << this << endl;
    }

 // 重载 > 
    bool operator > (const Int& c)const
     {
         return this->value > c.value;
     }

};

int main()
{
    Int a=1,b=2;

    cout << " a = " << a.value << endl;
    cout << " b = " << b.value << endl;

    if ( a > b )
        cout << " a > b" << endl;
    else
        cout << " a < b" << endl;

    return 0;
}

 运行结果:

3.赋值运算符=

#include <iostream>
#include <cstring>
using namespace std;

class Int
{
public:
    int value;

    Int(int v = 0) : value(v)//有默认参构造函数
    {
        cout << "Create Int: " << value << " " << this << endl;
    }

    ~Int() //析构函数
    {
        cout << "Destory Int: " << value << " " << this << endl;
    }

 // 重载 =
    Int& operator=(const Int& c)
    {
        if (this != &c) {  //防止自身赋值
            value = c.value;
        }
       cout << "operator="<<endl;
       return *this;
    }

};

int main()
{
    Int a=1,b;
    cout << " a = " << a.value << endl;

    b = a;
    cout << " b = " << b.value << endl;

    return 0;
}

 运行结果:

 //a=b->a.operator=(b)->operator=(&a,b)

4.类型强转

适用于类的对象值进行比较。(具体实例见重载++代码)

operator int() const  
	{
		return value;
	}

5.重载++/--

下面以重载(++)为例:

class Int
{
public:
    int value;

    Int(int v = 0) : value(v)//有默认参构造函数
    {
        cout << "Create Int: " << value << " " << this << endl;
    }

    ~Int() //析构函数
    {
        cout << "Destory Int: " << value << " " << this << endl;
    }
    
    Int(const Int& c) //拷贝构造函数
    {
        value = c.value;
        cout << "Copy Int:" << this << endl;
    }

    void Print() const //打印
    {
        cout << value << endl;
    }

//前置++
    Int& operator++() {
        this->value += 1;
        return *this;
    }

//后置++
   Int operator++(int)
   {
        Int old = *this;
        ++* this;  //从右向左结合
        return old;
    }
  
//强转
   operator int() const
   {
       return value;
   }
};


int main()  
{  
       cout << "前置++:"<<endl;
       for (Int i = 0; i < 3; ++i)
       {
           i.Print();
       }

       cout << endl<< "后置++:" << endl;
       for (Int i = 0; i < 3; i++)
       {
           i.Print();
       }
       return 0;
}
  

运行结果:

6.重载()

示例:

#include<iostream> 
#include <cstring>
using namespace std;

class Add
{
private:
	int sum;
public:
	Add() :sum(0){}

//在类型里面重载(),称为仿函数
	int operator()(const int a, const int b) //二元仿函数
	{
		sum = a + b;
		return sum;
	}
};

int main()
{
	int a = 10, b = 20, c = 0;
	c = Add()(a, b);
	cout << "c = "<< c << endl;
}

 运行结果:

c = 30

 分析:

c = Add()(a, b)-->c=Add().operator()(a,b)

 首先,由Add()构造函数构建了一个不具名对象;其次由该不具名对象调用()重载。

三、前置++和后置++辨析

1.前置++和后置++的运算规则

(1)a++;         (2)++a;

 分析:a++是先进行取值,后进行自增。++a是先进行自增,后进行取值。

2.返回引用和返回对象

 首先,我们再来看一下前置++和后置++的实现代码。

//前置++
    Int& operator++() {
        this->value += 1;
        return *this;
    }

//后置++
   Int operator++(int)
   {
        Int old = *this;
        ++* this;  //从右向左结合
        return old;
    }

两者的区别是:前置++返回引用(地址),后置++返回对象。

为什么会有上述区别?这是为了保持前置++和后置++的运算符特性。

1.前置++取成员变量自增后的值。故应分为以下步骤:

  • 成员变量先进行自增;
  • 返回对象的引用(地址)。

2. 后置++取成员变量自增前的值。故应分为以下步骤:

  • 先构建一个临时对象保存成员变量自增前的值;
  • 成员变量进行自增;
  • 返回临时对象。

前置++:a=++b->a=b.operator++()->a=operator(&b);

后置++:a=b++->a=b.operator++(0)->a=operator(&b,0);

3.为什么前置++返回引用,而后置++返回对象?

 前置++的成员变量的值会被修改并需要返回,不能返回普通对象。若返回引用,则直接修改并用this指针接收。【引用本质上是指针】

后置++返回对象为什么没有问题呢?因为后置++只需要自增并不返回。自增后值直接用this指针接收(++* this),并没有用临时对象接收并返回,临时对象返回的是自增前的值。

3.效率分析

下面对前置++和后置++的效率分析。

由运行结果可以看出,前置++的效率更高。

前置++:运行时只进行了一次对象的创建和析构,即对象i。

后置++:运行过程中不断地进行对象的创建和析构。

  • 先创建了对象i,打印 i=0;
  • 调用重载后置++,拷贝构造old对象和返回的临时对象(将亡值对象),析构old对象和临时对象,打印 i=1;以此类推...
  • 最后析构对象i。 

 【如有错误,欢迎指正,谢谢大家!】

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值