This warning is issued by the G++ compiler starting from GCC-13.
Clang++ 17 is happy with this code.
MSCV 19 produces the similar warning
(39): warning C4263: 'Derived &Derived::operator =(const Derived &)': member function does not override any base class virtual member function
(46): warning C4264: 'const Parent &Parent::operator =(int &)': no override available for virtual member function from base 'Parent'; function is hidden
(10): note: see declaration of 'Parent::operator ='
(5): note: see declaration of 'Parent'
Hiding the operator does not help either.
To me it looks like a flaw in C++ standard.
Why do I need to implement assignment operator in derived class instead of inheriting from parent class?
Let me try to elaborate on this topic:
- GCC 13.x and MSVC 19 generate the implicitly-defined copy operators even if they not supposed to do this.
- The implicitly-defined copy operator of the derived class hides the user defined assignment operator of the base class.
Deleted copy assignment operator
An implicitly-declared or explicitly-defaulted (since C++11) copy assignment operator for class T is undefined (until C++11)defined as deleted (since C++11) if any of the following conditions is satisfied:
...
- T has a non-static data member of a reference type.
...
I modified the code to avoid the generation of implicitly-defined copy assignment operator. But GCC and MSVC still want them.
Why the implicitly-defined copy assignment operators are generated in this case (by some compilers)?
Why some compilers claim that operator is hidden even it has different signature?
struct Parent
{
Parent(int &x) : _x(x) {};
virtual ~Parent() = default;
virtual const Parent & operator=(int &x)
{
x = 0;
return *this;
}
int &_x;
};
struct Derived : public Parent
{
Derived(int &x) : Parent(x) {};
virtual ~Derived() = default;
};
int main()
{
int x = 0;
Derived D1(x), D2(x);
#if (true)
/*
g++ 13.2: g++ --std=c++14 -o Woverloaded-virtual-test -Wall -Wextra Woverloaded-virtual-test.cpp
https://gcc.godbolt.org/z/PGoof73Md
__________________________________________________________________________________________________________
source>:6:28: warning: 'virtual const Parent& Parent::operator=(int&)' was hidden [-Woverloaded-virtual=]
6 | virtual const Parent & operator=(int &x)
| ^~~~~~~~
<source>:15:8: note: by 'Derived& Derived::operator=(const Derived&)'
15 | struct Derived : public Parent
| ^~~~~~~
Compiler returned: 0
*/
/*
mscv v19.37: /Wall /std:c++14
https://gcc.godbolt.org/z/P3PrcTjxs
__________________________________________________________________________________________________________
<source>(13): warning C4626: 'Parent': assignment operator was implicitly defined as deleted
<source>(19): warning C4626: 'Derived': assignment operator was implicitly defined as deleted
<source>(19): warning C4263: 'Derived &Derived::operator =(const Derived &)': member function does not override any base class virtual member function
<source>(19): warning C4264: 'const Parent &Parent::operator =(int &)': no override available for virtual member function from base 'Parent'; function is hidden
<source>(6): note: see declaration of 'Parent::operator ='
<source>(1): note: see declaration of 'Parent'
*/
#else
/*
g++ 13.2: g++ --std=c++14 -o Woverloaded-virtual-test -Wall -Wextra Woverloaded-virtual-test.cpp
__________________________________________________________________________________________________________
<source>:6:28: warning: 'virtual const Parent& Parent::operator=(int&)' was hidden [-Woverloaded-virtual=]
6 | virtual const Parent & operator=(int &x)
| ^~~~~~~~
<source>:15:8: note: by 'Derived& Derived::operator=(const Derived&)'
15 | struct Derived : public Parent
| ^~~~~~~
<source>: In function 'int main()':
<source>:27:10: error: use of deleted function 'Derived& Derived::operator=(const Derived&)'
27 | D1 = D2;
| ^~
<source>:15:8: note: 'Derived& Derived::operator=(const Derived&)' is implicitly deleted because the default definition would be ill-formed:
15 | struct Derived : public Parent
| ^~~~~~~
<source>:15:8: error: use of deleted function 'Parent& Parent::operator=(const Parent&)'
<source>:1:8: note: 'Parent& Parent::operator=(const Parent&)' is implicitly deleted because the default definition would be ill-formed:
1 | struct Parent
| ^~~~~~
<source>:1:8: error: non-static reference member 'int& Parent::_x', cannot use default assignment operator
Compiler returned: 1
*/
/*
clang++ 17.0.1: clang++ --std=c++14 -o Woverloaded-virtual-test -Wall -Wextra Woverloaded-virtual-test.cpp
https://gcc.godbolt.org/z/WzWfcqW3M
__________________________________________________________________________________________________________
<source>:111:8: error: object of type 'Derived' cannot be assigned because its copy assignment operator is implicitly deleted
112 | D1 = D2;
| ^
<source>:15:18: note: copy assignment operator of 'Derived' is implicitly deleted because base class 'Parent' has a deleted copy assignment operator
15 | struct Derived : public Parent
| ^
<source>:12:10: note: copy assignment operator of 'Parent' is implicitly deleted because field '_x' is of reference type 'int &'
12 | int &_x;
| ^
1 error generated.
Compiler returned: 1
*/
/*
msvc v19.37
https://gcc.godbolt.org/z/r4nss37K1
__________________________________________________________________________________________________________
<source>(13): warning C4626: 'Parent': assignment operator was implicitly defined as deleted
<source>(19): warning C4626: 'Derived': assignment operator was implicitly defined as deleted
<source>(19): warning C4263: 'Derived &Derived::operator =(const Derived &)': member function does not override any base class virtual member function
<source>(19): warning C4264: 'const Parent &Parent::operator =(int &)': no override available for virtual member function from base 'Parent'; function is hidden
<source>(6): note: see declaration of 'Parent::operator ='
<source>(1): note: see declaration of 'Parent'
<source>(94): error C2280: 'Derived &Derived::operator =(const Derived &)': attempting to reference a deleted function
<source>(19): note: compiler has generated 'Derived::operator =' here
<source>(19): note: 'Derived &Derived::operator =(const Derived &)': function was implicitly deleted because a base class invokes a deleted or inaccessible function 'Parent &Parent::operator =(const Parent &)'
<source>(13): note: 'Parent &Parent::operator =(const Parent &)': function was implicitly deleted because 'Parent' has a data member 'Parent::_x' of reference type
<source>(12): note: see declaration of 'Parent::_x'
*/
D1 = D2;
#endif
return x;
}
Original code is left here just for reference purpose.
#include <iostream>
using namespace std;
struct Parent
{
Parent() = default;
virtual ~Parent() = default;
virtual const Parent & operator=(int &x)
{
x = 0;
return *this;
}
};
struct Derived : public Parent
{
Derived() = default;
virtual ~Derived() = default;
#if (true)
/* Set to false to get rid of the following warning
g++ -o Woverloaded-virtual-test -Wall -Wextra Woverloaded-virtual-test.cpp
or
clang++ -o Woverloaded-virtual-test -Wall -Wextra Woverloaded-virtual-test.cpp
main.cpp:18:28: warning: ‘virtual const Parent& Parent::operator=(int&)’ was hidden [-Woverloaded-virtual=]
18 | virtual const Parent & operator=(int &x)
| ^~~~~~~~
main.cpp:48:24: note: by ‘constexpr Derived& Derived::operator=(const Derived&)’
48 | constexpr Derived& operator=(const Derived&) = delete;
| ^~~~~~~~
*/
#else
virtual const Parent & operator=(int &x) override
{
return Parent::operator=(x);
}
#endif
constexpr Derived& operator=(const Derived&) = delete;
void method(int &x)
{
x *= 2;
return;
}
};
int main()
{
cout<<"Hello World";
Derived D;
int x = 2;
D.method(x);
return x;
}
We have a
Derived& operator=(const Derived&)whether we define it or not, and that hides the base classoperator=name.Derived& operator=(const Derived&) = deletedoes not have the effect of making it as if the function never existed. The name exists, but no longer has a function definition.This
= deletedeclaration still has the effect of hiding the base-class function.We can fix this error the same way we make any base-class names participate in overload resolution - we make it visible again with
usingin the subclass:(I'll ignore the issue of whether a virtual
operator=()is a good idea or not...)