【问题标题】:Problem with operator inheritance and cpp core guidelines c.128运算符继承问题和 cpp 核心指南 c.128
【发布时间】:2020-05-29 01:13:03
【问题描述】:

我有以下代码(我在这里删除了一些不重要的代码):

class State {
public:

  virtual void enter() = 0;
  virtual void update() = 0;
  virtual void exit() = 0;
};

class SimpleState : public State {
public:

  SimpleState() = default;
  SimpleState(const SimpleState&) = default;
  SimpleState(SimpleState&&) = default;
  virtual ~SimpleState() = default;

public:

  void enter() override;
  void update() override;
  void exit() override;

public:

  SimpleState& operator=(const SimpleState&) = default;
  SimpleState& operator=(SimpleState&&) = default;
};

由于我已经定义了析构函数并且我还需要定义其他东西(如果我记得,规则为 5),因此我添加了默认运算符以解决指导警告。

如果我通过启用 cpp 核心指南使用 Visual Studio 2019 构建它,我会收到以下警告:

SimpleState.hpp: warning C26456: Operator 'SimpleState::operator=' hides a non-virtual operator 'State::operator=' (c.128).
SimpleState.hpp: warning C26456: Operator 'SimpleState::operator=' hides a non-virtual operator 'State::operator=' (c.128).

我想摆脱它,所以我按以下方式更改了代码:

class State {
public:

  virtual void enter() = 0;
  virtual void update() = 0;
  virtual void exit() = 0;

public:

  virtual State& operator=(const State&) = 0;
  virtual State& operator=(State&&) = 0;
};

class SimpleState : public State {
public:

  SimpleState() = default;
  SimpleState(const SimpleState&) = default;
  SimpleState(SimpleState&&) = default;
  virtual ~SimpleState() = default;

public:

  void enter() override;
  void update() override;
  void exit() override;

public:

  SimpleState& operator=(const SimpleState&) override = default;
  SimpleState& operator=(SimpleState&&) override = default;
};

但在这种情况下,我会收到以下错误:

SimpleState.hpp: error C3668: 'SimpleState::operator =': method with override specifier 'override' did not override any base class methods
SimpleState.hpp: error C3668: 'SimpleState::operator =': method with override specifier 'override' did not override any base class methods

我做错了什么以及如何删除指南警告?

【问题讨论】:

  • 我建议你改用the rule of zero。让编译器为您生成构造函数、析构函数和赋值运算符。
  • 我一开始就这样做了,我得到了另一个 cpp 核心指南警告,告诉我虚拟析构函数对于派生类是显式的。我已经添加了它,然后我得到了这个问题。
  • @Jepessen 核心准则是准则,而不是更多。您必须在每种情况下评估是否有必要进行更改,并且您需要阅读github.com/isocpp/CppCoreGuidelines/blob/master/… 中的相应部分以确定如何以及是否采取行动。仅仅因为警告说明而添加东西只会使情况变得更糟。
  • 那么请阅读the rule of three的第一句(同样适用于五法则):“如果一个类需要一个用户-定义 析构函数...”(强调我的)。如果你没有明确定义(实现)你的析构函数,你就没有违反“规则”。
  • 好的,谢谢你的建议。我们现在开始测试这些指南,因此我们需要详细说明使用它们的更多经验。

标签: c++ visual-studio visual-studio-2019 cpp-core-guidelines


【解决方案1】:

我怀疑这种情况下的 C26456 警告是一个错误,另请参阅 https://developercommunityapi.westus.cloudapp.azure.com/content/problem/617702/c26456-false-positive-with-operator-in-derived-cla.htmlhttps://developercommunity.visualstudio.com/content/problem/228085/c-core-check-false-positive-c26434.html

引用的核心准则子句C.128 仅适用于虚成员函数,但operator= 在您的基类中不是虚函数,也没有与派生类中相同的签名,因此没有理由这样做申请。


确保您确实需要SimpleState 中的析构函数声明。您在基类State 中有虚函数,这似乎表明您想多态地使用State,并且对象可能通过State 指针而不是SimpleState 指针被销毁。在这种情况下,State 需要声明一个虚拟析构函数,而不是 SimpleState

如果您在State 中声明了虚拟析构函数,那么您将不需要在SimpleState 中声明任何析构函数,它将从State 继承虚拟析构函数。然后SimpleState 可以遵循零规则,不需要任何复制/移动赋值运算符和复制/移动构造函数声明,这是首选方式。

【讨论】:

  • 这是我的初衷。我添加了虚拟析构函数,因为 cpp 核心准则抱怨它丢失的事实,所以我添加了它,然后他们抱怨规则 5。所以基本上我可以返回到我已经实现的原始代码SimpleState 中的零规则。
  • @Jepessen 是的,但不要忘记将virtual ~State() = default; 添加到State。然后,您可以默认 State 中的复制/移动操作以满足它的 5 规则。
【解决方案2】:

基本上,为了覆盖任何方法,覆盖方法的签名需要与原始方法签名相同。但是,在您的情况下,签名是不同的 SimpleState& operator=(const SimpleState&)State& operator=(const State&)。因此,您没有覆盖原始方法,而是将方法声明为覆盖,因此会出现错误。

【讨论】:

  • State& operator=(const State&) 首先不是虚拟的,所以它永远不能被覆盖,这就是为什么我怀疑警告是一个错误。
猜你喜欢
  • 2011-04-22
  • 1970-01-01
  • 2017-12-17
  • 2011-08-12
  • 2021-06-07
  • 2012-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多