提问人:emerg.reanimator 提问时间:10/28/2023 最后编辑:emerg.reanimator 更新时间:10/30/2023 访问量:92
-Woverloaded-virtual 带有默认的浅拷贝运算符
-Woverloaded-virtual with default shallow copy operator
问:
此警告由 G++ 编译器从 GCC-13 开始发出。
Clang++ 17 对这段代码很满意。
MSCV 19 产生类似的警告
(39):警告 C4263:“Derived &Derived::operator =(const Derived &)”:成员函数不覆盖任何基类虚拟成员函数
(46): 警告 C4264: 'const Parent &Parent::operator =(int &)': 没有可用于基 'Parent' 的虚拟成员函数的覆盖;功能是隐藏的
(10): 注意:参见 'Parent::operator =' 的声明
(5):注:见“父”声明
隐藏运算符也无济于事。
对我来说,这看起来像是 C++ 标准中的一个缺陷。
为什么我需要在派生类中实现赋值运算符,而不是从父类继承?
让我试着详细阐述这个话题:
- GCC 13.x 和 MSVC 19 生成隐式定义的复制运算符,即使它们不应该这样做。
- 派生类的隐式定义的复制运算符隐藏了基类的用户定义的赋值运算符。
隐式声明或显式默认(自 C++11 起)副本 类 T 的赋值运算符未定义(直到 C++11)定义为 如果满足以下任一条件,则删除(自 C++11 起):
...
- T 具有引用类型的非静态数据成员。
...
我修改了代码以避免生成隐式定义的复制赋值运算符。但 GCC 和 MSVC 仍然需要它们。
为什么在这种情况下会生成隐式定义的复制赋值运算符(由某些编译器)?
为什么有些编译器声称运算符是隐藏的,即使它有不同的签名?
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;
}
此处保留原始代码仅供参考。
#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;
}
答:
1赞
Toby Speight
10/28/2023
#1
我们有一个是否定义它,它隐藏了基类名称。Derived& operator=(const Derived&)
operator=
Derived& operator=(const Derived&) = delete
不会使它像函数从未存在过一样。该名称已存在,但不再具有函数定义。
此声明仍然具有隐藏基类函数的效果。= delete
我们可以像让任何基类名称参与重载解析一样修复这个错误 - 我们在子类中再次看到它:using
constexpr Derived& operator=(const Derived&) = delete;
using Parent::operator=;
(我将忽略虚拟是否是一个好主意的问题......operator=()
评论
0赞
emerg.reanimator
10/28/2023
感谢您的回复!在这种情况下,警告消失了。但是,我不得不承认,这基本上是在派生类中覆盖 operator= 的简短形式。
0赞
emerg.reanimator
10/29/2023
此 = delete 声明仍然具有隐藏基类函数的效果。即使未隐藏浅拷贝运算符,也会发出警告: ' 10 |virtual const Parent & operator=(int &x)' ' |^~~~~~~~' ' 17 |struct 派生:public Parent' ' |^~~~~~~`Woverloaded-virtual-test.cpp:10:28: warning: ‘virtual const Parent& Parent::operator=(int&)’ was hidden [-Woverloaded-virtual=]
Woverloaded-virtual-test.cpp:17:8: note: by ‘constexpr Derived& Derived::operator=(const Derived&)’
0赞
Toby Speight
10/29/2023
是的,因为您没有编写(或)的默认值隐藏了基类函数。同样的修复程序解决了这个问题。operator=()
=delete
0赞
emerg.reanimator
10/29/2023
同样的修复程序解决了这个问题。正确,但这意味着对于每个不需要重写方法的派生类,我需要显式引用基类运算符 ()。可行的解决方案可能真的是使用其他运营商。如果我替换 with,那么警告就会消失,而无需向派生类添加额外的代码。operator=()
using Parent::operator=
operator=()
operator<<()
0赞
Toby Speight
10/29/2023
是的,没错 - 每个派生类都需要它。与的比较是没有意义的,因为它不是按原样隐式提供的。using
operator<<()
operator=()
评论
#else
override
virtual