为什么我的赋值运算符不被调用?

时间:2011-09-11 18:43:04

标签: c++ operator-overloading assignment-operator

我很困惑......为什么我的任务操作员不会在这里被调用?

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        __debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this):
    }
};

struct myderived : mybase<myderived>
{
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;

    return 0;
}

4 个答案:

答案 0 :(得分:6)

因为derived中的默认赋值运算符将隐藏重载的基数。

答案 1 :(得分:5)

自动生成的复制赋值运算符mybase::operator=

myderived::operator= 隐藏

您可以使用using声明使派生类中的基类运算符可见。

编辑:为每个请求添加了示例:

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        //__debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this);
    }
};

struct myderived : mybase<myderived>
{
    using mybase<myderived>::operator=;
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;
}

使用Visual C ++ 10.0和Comeau Online可以很好地编译。实际上,后者意味着它是很好的标准C ++。但是,代码不能使用MinGW g ++ 4.4.1(编译器错误)进行编译。

编辑2:实际上,现在检查,使用Visual C ++ 10.0进行编译,但不调用基类操作符。所以也许g ++是正确的。 using通常是引入基类赋值运算符(或其他)的方法,但在这种情况下它与派生类'复制赋值运算符具有相同的签名,我还不知道Visual C ++是否有行为是否正确 - 这是该语言的一个极端情况。

编辑3:我检查了N3290(与C ++ 11完全相同的标准草案),它说

  

<强>§12.8/ 18:
  如果类定义未显式声明复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认值(8.4)。

我个人解释说,在using声明的情况下,类“声明”了一个复制赋值运算符,因此不应该隐式生成(因为它似乎是Visual C ++ 10.0所做的)。但是,这是该语言的一个极端情况。其他人可能会对此有不同的解释,如上所述,编译器也有所不同!

干杯&amp;第h。,

答案 2 :(得分:3)

这一行:

a = b;  

显然要求myderived重载了复制赋值运算符。它可以由编译器隐式生成,也可以由myderived类明确定义:

  

12.8复制类对象[class.copy]

     

9. 用户声明的复制赋值运算符X::operator=是a   类X的非静态非模板成员函数,只有一个   类型XX&const X&volatile X&const volatile X&的参数。

您已尝试在mybase类中创建用户声明的复制赋值运算符,但根据C ++标准,它实际上并不是复制赋值运算符。想象一下,如果我们使用Thismyderived进行了类型替换:

// Hypothetical class generated by the compiler from
// the mybase template class with This = myderived
struct mybase_myderived 
{
    myderived& operator =(const myderived &other) 
    { 
        // ...
    } 
};

显然,这不是复制赋值运算符,因为参数other的类型为const myderived&,而不是const mybase&。如果other参数属于const mybase&类型,或mybasemybase&,那么它将是一个有效的复制赋值运算符,可以通过默认的复制赋值调用myderived中的运算符。但它不是在这种情况下,所以编译器仍然为mybase生成一个默认的复制赋值运算符,在这种情况下当然不会做任何事情。

myderived中编译器生成的默认复制赋值运算符在mybase中调用编译器生成的默认复制赋值运算符。所以最终会发生什么,因此,永远不会调用operator=(const myderived &other)重载。

编译器不直接调用mybase::operator=的原因是因为它被myderived中编译器生成的复制赋值运算符隐藏了,正如Alf P. Steinbach在{{3}中指出的那样。 }}

答案 3 :(得分:2)

因为编译器在myderived中引入了默认赋值运算符。覆盖它并自己调用您的基本赋值运算符。或者也许使用指令会有所帮助?尝试在myderived body中使用mybase :: operator =。