Many, many, many posts about inheriting operator=
, with the usual answer being "it's overshadowed by the implicitly defined one, use using Base::operator=
if you know what you're doing".
Here's a hopefully slightly different question. Consider the following in which base class A
knows about the exact type of the derived class:
#include <iostream>
template <typename E>
struct A {
E& operator= (const E& other) {
std::cout << "A<E>::op=\n";
return *(E*)this;
}
E& operator= (E& other) {
std::cout << "A<E>::op no const=\n";
return *(E*)this;
}
};
struct B : public A<B> {
using A<B>::operator=;
};
int main () {
B x, y;
x = y;
const B z;
x = z;
}
In the main
function, when calling x = y
, the method E& A<E>::operator= (E& other)
with E = B
is called, as expected. However, x = z
does not call E& A<E>::operator= (const E& other)
.
Why? (Note that this is a question about behavior, not style :-) )
Why?
Because x = z
uses the implicitly defined
B& B::operator=(const B&)
and the implicitly defined
A& A::operator=(const A&)
// instantiated as:
A<B>& A<B>::operator=(const A<B>&)
The implicit definitions are not removed just because you bring the base class operators out of hiding. See [class.copy]/24:
A using-declaration ([namespace.udecl]) that brings in from a base class an assignment operator with a parameter type that could be that of a copy/move assignment operator for the derived class is not considered an explicit declaration of such an operator and does not suppress the implicit declaration of the derived class operator; the operator introduced by the using-declaration is hidden by the implicitly-declared operator in the derived class.
The reason why the other case, x = y
, instead uses E& A::operator= (E& other)
is because it's a better match since it doesn't need to convert y
to a const&
.