2012-07-09 82 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. */ } 
相关问题