【 聲明:版權所有,歡迎轉載,請勿用於商業用途。 聯系信箱: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;}
};
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 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;
}
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;
}
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指向的內存空間就存在了很大的不確定性,這就是算術符重載的陷阱。