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;
    }

它会起作用的。你有什么想法为什么初始功能不起作用?

4

2 回答 2

7

您的赋值运算符的模板版本不会禁止为您的类生成编译器提供的非模板复制赋值运算符。编译器将隐式声明和定义具有以下签名的复制赋值运算符

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

在复制分配的重载解决过程中,编译器提供的版本获胜(因为它更专业)。

您的模板版本的赋值运算符只会被考虑用于转换赋值。例如,如果在某些时候您想要将A<int>对象分配给A<double>对象,则将使用您的模板版本的赋值运算符。但是,当您分配A<int>A<int>您的运算符时,将被忽略,因为编译器声明的版本是更好的匹配。

当您声明自己的副本分配版本时

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

签名,它会抑制编译器生成的签名。你的版本被使用。

这意味着,如果您想拥有自己的复制赋值运算符模板转换赋值运算符,则需要在类中显式实现这两者

PS作为'@Cheers 和hth。- Alf' 正确指出,您的赋值运算符模板版本在一般情况下甚至无效。指针通常具有不同的不相关类型this&obj不允许比较不同不相关类型的指针。

于 2012-07-09T17:12:21.103 回答
4

T& operator=(T const&)如果您没有定义自己的复制赋值运算符,则编译器会自动声明和定义带有签名的复制赋值运算符。

您的赋值运算符模板不是复制赋值运算符,因为它是一个模板(模板永远不是复制赋值运算符)。

在您的示例中,myobjectsandyourobjects都是 type A<int>operator=编译器可以选择两种重载:

  1. A<int>& operator=(A<int> const&),由编译器隐式提供,或
  2. A<int>& operator=(A<int> const&),您的模板的专业化。

您会注意到这两个具有完全相同的签名。重载决议的规则之一是在所有其他条件相同的情况下,非模板比模板更可取。隐式声明的复制赋值运算符不是模板,并且您的重载是模板,因此operator=选择了隐式声明的。

要禁止隐式声明的复制赋值运算符,您需要声明并定义自己的:

A& operator=(A const&) { /* etc. */ }
于 2012-07-09T17:13:02.923 回答