版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
在算术符重载里面,“=”重载可能是最经常使用的一种。但是好多人就误以为在函数中,凡是类出现“=”的地方,那就是调用算术符重载,其实不然。为什么呢?我们可以看看下面的代码。首先,我们定义一个基本类:
-
class
data
-
{
-
char*
value;
-
int number;
-
public:
-
explicit data(int num = 0){
-
if(num){
-
number = num;
-
value = (
char*)malloc(num);
-
}
-
}
-
-
data(
const data& d){
-
number = d.get_number();
-
value = (
char*)malloc(d.get_number());
-
memmove(
value, d.get_point(), d.get_number());
-
}
-
-
~data(){
-
if(number)
-
free(
value);
-
}
-
-
data&
operator=(
const data& d){
-
if(number)
-
free(
value);
-
number = d.get_number();
-
value = (
char*)malloc(d.get_number());
-
memmove(
value, d.get_point(), d.get_number());
-
return *
this;
-
-
}
-
-
int get_number() const {
return number;}
-
char* get_point()
const {
return
value;}
-
};
定义好了函数之后,我们就开始对这个类进行调用,同样代码如下所示:
-
45: data m(10);
-
0040108D push 0Ah
-
0040108F lea ecx,[ebp-14h]
-
00401092
call @ILT+
30(
data::
data) (
00401023)
-
00401097 mov dword ptr [ebp
-4],
0
-
46:
data p = m;
-
0040109E lea eax,[ebp-14h]
-
004010A1 push eax
-
004010A2 lea ecx,[ebp-1Ch]
-
004010A5
call @ILT+
35(
data::
data) (
00401028)
-
004010AA mov
byte ptr [ebp
-4],
1
-
47: p = m;
-
004010AE lea ecx,[ebp-14h]
-
004010B1 push ecx
-
004010B2 lea ecx,[ebp-1Ch]
-
004010B5
call @ILT+
5(
data::
operator=) (
0040100a)
-
48: }
上面共有三句话,我们逐一进行分析:
45句:定义了一个临时变量,调用data的构造函数
46句:出现了一个临时变量p,这里发现data类并没有调用算术符重载函数,而是调用了data的构造函数,根据45句所示,调用的肯定不是普通的构造函数,那么剩下的结果只能是拷贝构造函数
47句: 和46句的代码是一致的,但是此时调用的函数才是算术符重载函数
所以说,出现“=”的地方未必调用的都是算术符重载函数,也有可能是拷贝构造函数。那么什么时候是拷贝构造函数,什么时候是算术符重载函数呢?判断的标准其实很简单。如果临时变量是第一次出现,那么调用的只能是拷贝构造函数,反之如果变量已经存在,就像47句一样,那么调用的只能是算术符重载函数,但是我们这里定义的算数符重载函数有一个陷阱,不知道大家看出来没有?
我提示大家一下,这里的算术符重载需不需要判断拷贝的是不是自己呢?
-
void process()
-
{
-
data m(10);
-
data p = m;
-
p = p;
-
}
这里最后一句,如果算术符可以自己拷贝给自己,代码正常编译和运行都没有问题,但是在某些情况下会出现很多意想不到的情况。大家可以跟着我的思路来:
-
data&
operator=(const
data& d){
-
if(
this == &d)
/* check whether it is self-copy action */
-
return *
this;
-
-
if(number)
-
free(value);
-
number = d.get_number();
-
value = (char*)malloc(d.get_number());
-
memmove(value, d.get_point(), d.get_number());
-
return *
this;
-
-
}
如果上面的代码没有判断复制的对象是不是自己,那么我们发现实际上value的数据实际上已经free掉了。那么此时重新分配内存,拷贝的数据只有天知道是什么数据。原来value指向的内存空间就存在了很大的不确定性,这就是算术符重载的陷阱。
【后记: 自此用汇编看C++系列全部结束,下面我们将开始数据结构和算法的讨论,欢迎关注】