开发者

Why isn't my assignment operator getting called?

I'm confused... why isn't my assignment operator getting called here?

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()
{
    myderive开发者_StackOverflow中文版d a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;

    return 0;
}


Because the default assignment operator in derived will hide the overloaded in base.


mybase::operator= is hidden by the automatically generated copy assignment operator myderived::operator=.

You can use a using declaration to make the base class operator visible in the derived class.

EDIT: added example per request:

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

This compiles fine with Visual C++ 10.0 and with Comeau Online. The latter means, in practice, that it's good standard C++. However, the code does not compile with MinGW g++ 4.4.1 (compiler bug).

EDIT 2: Actually, checking now, with Visual C++ 10.0 it compiles but the base class operator is not invoked. So maybe g++ is correct. using is generally the way to bring in a base class assignment operator (or whatever), but in this case it has the same signature as the derived class’ copy assignment operator, and I do not yet know whether Visual C++ behavior is correct or not – it is a corner case of the language.

EDIT 3: I checked N3290 (the standard draft that is identical to C++11), and it says

§12.8/18:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4).

I personally interpret that as saying that with the using declaration in place the class “declares” a copy assignment operator, and that one should therefore not be implicitly generated (as it seems that Visual C++ 10.0 does). However, this is a corner case of the language. Others may possibly interpret this differently, and as noted above, compilers differ!

Cheers & hth.,


This line:

a = b;  

obviously requires that myderived have overloaded the copy assignment operator. It can be implicitly generated by the compiler, or defined by the myderived class explicitly:

12.8 Copying class objects [class.copy]

9. A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.

You have attempted to create a user-declared copy assignment operator in your mybase class, but it's not actually a copy assignment operator according to the C++ standard. Imagine if we did a type substitution for This with myderived:

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

Clearly that's not a copy assignment operator, because the parameter other is of type const myderived&, not const mybase&. Had the other parameter be of type const mybase&, or mybase, or mybase&, then it would be a valid copy assignment operator, which can be called by the default copy assignment operator in myderived. But it isn't in this case, so the compiler still generates a default copy assignment operator for mybase, which of course does nothing in this case.

The compiler-generated default copy assignment operator in myderived calls the compiler-generated default copy assignment operator in mybase. So what ends up happening, as As a result, the operator=(const myderived &other) overload is never called.

The reason why the compiler doesn't just call mybase::operator= directly is because it's been hidden by the compiler-generated copy assignment operator in myderived, as Alf P. Steinbach points out in this answer.


Because the compiler introduces the default assignment operator in myderived. Override it and call your base assignment operator yourself. Or perhaps a using directive will help? Try using mybase::operator= in myderived body.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜