利用operator关键字在对象间进行赋值的几点注意事项

ps:http://www.cnblogs.com/uniqueliu/archive/2011/09/08/2170452.html

=====================问题提出=====================

      众所周知,我们都会用operator关键字来重载原先系统自带的运算符,来达到自己的目的。但是当我们在对象中运用这种方法的时候,我们还是应该考虑下整个程序性能的问题。比如说对于下面这个程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
 
class num
{
public:
    num(int i){n=i;cout<<"构造函数正在运行!\n";}//constructor
    void setNum(int val){n=val;}
    int getNum() const {return n;}
    /*void operator++(num i){};*/
    void operator++();
private:
    int n;
};
 
/*void num::operator++(num i)*/
void num::operator ++()
{
    int temp=++n;
    setNum(temp);
}
 
int main()
{
    num i(1);
    cout<<"对象i的值为"<<i.getNum()<<endl;
    ++i;
    cout<<"把i自加后,对象i的值为"<<i.getNum()<<endl;
    return 0;
}

      这个程序的作用想必大家都应该很清楚了嘛,就是利用operator将++运算符重载,使之能够适应如程序中第27行的情况。该程序的运行结果很了然:

      但是,如果我们把程序里面的第27行换成下面这句话:

num i2=++i;

      那么这个程序就会立即报错鸟~~原因其实很简单,我们在这里调用++i其实就是相当于调用下面这句话:

num i2=i.operator++();

      而我们清楚的知道,在程序的第11行里面清楚明了地写着,operator++()这个函数返回值为空!所以程序当然会报错了啊!

=====================解决之道=====================

      要想解决这个问题,我们其实有三种方法可以选择,一种比一种效率高。下面,我就一种一种地来介绍...

      方法1.创建临时对象

这个方法的思路其实很简单,就是把operator++()函数稍微改一下,使它能够传回对象,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
 
class num
{
public:
    num(int i){n=i;cout<<"构造函数正在运行!\n";}//constructor
    void setNum(int val){n=val;}
    int getNum() const {return n;}
    num operator++();
private:
    int n;
};
 
num num::operator ++()
{
    num temp(0);  //创建一个临时对象
    ++n;
    temp.setNum(n);
    return temp;
}
 
int main()
{
    num i(1);
    cout<<"对象i的值为"<<i.getNum()<<endl;
    num i2=++i;
    cout<<"对象i2的值为"<<i2.getNum()<<endl;
    return 0;
}

      程序截图:

      这种方法的逻辑其实很清楚。我们先把创建一个temp对象,然后再把n自加之后的值传递到temp中,最后返回temp给i2。但是这种方法的效率极其的不高,由于我们知道,创建一个临时对象并且在程序结束的时候销毁它,这样会占用大量的系统资源,这就造成了程序的运行速度减慢,这在某种程度上是不能接受的。那么还有没有什么好的方法可以解决这个问题呢?

上面我提出了利用operator重载运算符来实现对象的自加运算,而在文章的最后,我提出了一个在性能上面的问题,就是创建对象。那么我们能不能不要创建对象就可以完成赋值操作呢?

      答案当然是可以的了,我们只需要利用this指针。inweithis指针就是当前对象的标签。那么实际上我们只需要将当前对象的成员变量自加,然后返回用this指针指向的当前对象就可以了。具体程序如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
class num
{
public:
    num(int i) {n=i;cout<<"构造函数执行!"<<endl;}
    num(const num &s){this->n=s.n;cout<<"拷贝构造函数执行!"<<endl;}
    int get()const{return n;}
    num operator ++()
    {
        ++n;
        return *this;
    }
private:
    int n;
};
int main()
{
    num i(1);
    cout<<"i="<<i.get()<<endl;
    num x=i++;
    cout<<"x="<<x.get()<<endl;
    return 0;
}

      首先我们关注这个程序的第7行,这里我们定义了一个复制构造函数,它的作用就是在程序12行返回this指针所指向的对象之后能够将其复制给新的对象。我们在程序的第12行返回this指针的时候,其实返回的是this指针所指向的对象,在这里是i。而我们在程序的第11行将i的数据成员n进行了自加,所以返回的this所指向的i中间的n这个时候应该就是2,而不是1。

      返回之后,编译器就会调用位于程序第7行的复制构造函数。此时的参数应该是这样的,我们给复制构造函数传递的参数应该是i,而函数体中的this->n中的this实际上指的应该是位于程序第21行所创建的对象x。这个时候,我们可以把程序第21行这句话理解成  

num x(i.operator());

      因为返回的是this指针,即自加之后的对象i,所以说此时编译器利用复制构造函数将对象x也复制成i的样子,即x.n=2。

      程序的输出证明了我们的想象:

posted on 2015-05-08 00:42  会敲键盘的猩猩  阅读(174)  评论(0)    收藏  举报