2012-07-09 103 views
2

在下面的代碼,我說明運算符重載的例子:爲什麼運算符重載失敗?

#include <iostream> 
using namespace std; 

template <typename T> 
class A 
{ 
public: 
    A() {}; 
    A(T &obj) {value = obj;}; 
    ~A() {}; 
    T value; 
    template <typename E> 
    A<T>& operator = (const A<E> &obj) 
    { 
     cout<<"equal operator"<<endl; 
     if(this == &obj) 
      return *this; 

     value = obj.value; 
     return *this; 
    } 

}; 



int main() 
{ 
    int temp; 
    temp = 3; 
    A<int> myobjects(temp); 
    cout<<myobjects.value<<endl; 

    temp = 7; 
    A<int> yourobjects(temp); 
    yourobjects = myobjects; 
    cout<<yourobjects.value<<endl; 



    return 0; 
} 

然而,當我調試這個程序,我發現主程序不會調用等於運算符重載功能。但是,如果我通過以下方式更改相同的運營商:

A<T>& operator = (const A<T> &obj) 
    { 
     cout<<"equal operator"<<endl; 
     if(this == &obj) 
      return *this; 

     value = obj.value; 
     return *this; 
    } 

它會工作。你有什麼想法,爲什麼最初的功能不起作用?

+2

需要注意的是,最好把這種現象稱爲了_assignment_操作。 _equal_運算符是'=='。 – 2012-07-09 17:21:42

回答

7

您的賦值運算符的模板版本不會禁止爲您的類生成編譯器提供的非模板複製賦值運算符。編譯器將implictly聲明並具有以下簽名

A<T>& operator =(const A<T>&); 

在拷貝賦值編譯器提供的版本勝重載決策過程定義拷貝賦值運算符(因爲它是更專業的)。

您的模板版本的賦值運算符只會被考慮用於轉換賦值。例如。如果在某個時候您想要將A<int>對象分配給A<double>對象,則將使用您的賦值運算符的模板版本。但是,當您將A<int>指定爲A<int>時,您的操作符會被忽略,因爲編譯器聲明的版本更好。

在聲明自己的副本,任務的版本

A<T>& operator =(const A<T>&); 

簽名,它抑制了編譯器生成一個。您的版本已被使用。

這意味着,如果你想擁有自己的拷貝賦值運算符以及爲模板變換,賦值運算符,你需要明確實現類

P.S.正如'@Cheers和hth。 - Alf'正確地指出,您的賦值運算符的模板版本在一般情況下甚至不適用。指針this&obj通常具有不同的不相關類型。您不允許比較不同無關類型的指針。

+1

重新編輯,運算符定義中的比較確保在一般情況下它不會編譯。因此操作員將不會被使用。 – 2012-07-09 17:16:00

4

如果您未定義自己的複製賦值運算符,則編譯器會自動聲明並定義複製賦值運算符,其簽名爲T& operator=(T const&)

您的賦值運算符模板不是複製賦值運算符,因爲它是一個模板(模板從不是複製賦值運算符)。

在你的例子中,myobjectsyourobjects都是A<int>類型。有兩個operator=重載編譯器可以選擇:

  1. A<int>& operator=(A<int> const&),這是隱式由編譯器提供,或
  2. A<int>& operator=(A<int> const&),模板的一個特例。

你會注意到這兩個簽名都完全相同。重載解析的一個規則是所有其他事物都相同,非模板比模板更可取。隱式聲明的複製賦值運算符不是模板,並且您的超載是模板,所以隱式聲明的operator=被選中。

爲了抑制隱式聲明的拷貝賦值運算符,你需要聲明和定義自己:

A& operator=(A const&) { /* etc. */ } 
相關問題