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 classX
with exactly one parameter of typeX
,X&
,const X&
,volatile X&
orconst 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.
精彩评论