【问题标题】:How to call a non-const function within a const function (C++)如何在 const 函数中调用非常量函数 (C++)
【发布时间】:2011-06-27 20:52:47
【问题描述】:

我有一个看起来像这样的旧函数:

int Random() const
{
  return var_ ? 4 : 0;
}

我需要在该遗留代码中调用一个函数,使其现在看起来像这样:

int Random() const
{
  return var_ ? newCall(4) : 0;
}

问题是我收到了这个错误:

In member function 'virtual int Random() const':
class.cc:145: error: passing 'const int' as 'this' argument of 'int newCall(int)' discards qualifiers

现在我知道,为了修复这个错误,我可以让我的 newCall() 成为一个 const 函数。但是我必须在newCall() 中进行几个函数调用,所以现在我必须将所有这些函数调用都设为常量。依此类推,直到最终我觉得我的程序的一半将是 const。

我的问题:有没有办法在 Random() 中调用不是 const 的函数?或者是否有人对如何在Random() 内实现newCall() 而不使我的程序的一半成为常量有任何想法。

谢谢

-乔什

【问题讨论】:

  • 你可以让 Random() 非常量。
  • 我愿意,但 Random() 是我无法真正触及的遗留代码。
  • 那 4 个是用无偏的骰子选择的吗(从而使它真正随机)。
  • 查看错误信息,我徘徊也许您的问题在其他地方?请注意“将 const int 传递为 'this'”。听起来很奇怪,也许 4 参数被解释为this?为什么?
  • 问题不是要声明多少个函数const,而是这些函数是否真的是const:它们是否修改了对象的任何成员?如果不是,则将它们标记为 const。

标签: c++ function constants const-correctness const-cast


【解决方案1】:
int Random() const
{
  return var_ ? const_cast<ClassType*>(this)->newCall(4) : 0;
}

但这不是一个好主意。尽可能避免!

【讨论】:

  • 如您所说,如果您确实需要使用const_cast 来完成此操作,请尝试重构您的设计。
  • 有时候你忍不住..以前的程序员过度设计,使用语言中所有的花哨功能,然后在他的代码变得太乱和无法维护后离开公司..跨度>
  • 最后是合理的答案,而不是“你不能那样做”......总有一些情况你应该甚至鼓励这样做。例如,如果您想提供 const 接口方法并为非常量实现使用相同的逻辑,该怎么办?例如,想象一下树行走逻辑。您是否应该复制粘贴它来为所有节点编写 const 访问器和非 const 访问器?或者只是为这些任务创建干净的 const 和非 const 包装器?
【解决方案2】:

应该更改您的程序以正确使用/声明 const...

另一种方法是使用 const_cast。

【讨论】:

  • 错误地使用 const_cast(这是会发生的事情)将导致一场彻底的灾难。
  • 感谢您的建议,我最终将 newCall() 和 newCall() 下面的函数都更改为 const,因为我不想错误地使用 const。
  • @Grammin 不客气。正确声明它有很多好处。最重要的 (imo) 是它在维护和可读性方面节省了大量时间。当程序发生变化时,编译器可能会快速检测到不当使用。一个副作用是 c++ 开始编写如此多的 const,您认为在某些情况下如果 const 是默认值会很好,并且使用关键字来指定突变 :)
  • 还有另一种方式,使用代理。 stackoverflow.com/questions/8325400/…
  • @AlexandreVaillancourt 如果您只需要示例用法,这里是:docs.microsoft.com/en-us/cpp/cpp/const-cast-operator -- 尽可能避免擦除 const 并了解什么是 UB。当然,const_cast 优于 C 风格的转换——当您(真正)需要它时。在处理编写良好的现代 API 时,您需要它的情况应该很少见。我主要在处理 C API 时使用它。幸运的是,我不必经常使用它。最后,我不推荐的行应该是这样的:return var_ ? const_cast&lt;TYPE*&gt;(this)-&gt;newCall(4) : 0;
【解决方案3】:
const_cast<MyClass *>(this)->newCall(4)

只有在您确定 newCall 不会修改“this”时才这样做。

【讨论】:

    【解决方案4】:

    这里有两种可能性。首先,newCall 及其所有被调用者实际上都是非修改函数。在这种情况下,您绝对应该通过并标记它们const。你和未来的代码维护者都会感谢你让代码更容易阅读(这里是个人经验)。其次,newCall 实际上确实改变了对象的状态(可能通过它调用的函数之一)。在这种情况下,您需要中断 API 并使 Random 非 const 以正确地向调用者指示它修改了对象状态(如果修改仅影响物理常量而不影响逻辑常量,您可以使用可变属性并传播 const )。

    【讨论】:

      【解决方案5】:

      不使用 const 类型转换,您能否尝试在 Random() 方法中创建该类的新实例?

      【讨论】:

        【解决方案6】:

        const 限定符断言类的实例this 在操作后将保持不变,这是编译器无法自动推断的。

        const_cast 可以使用,但它是邪恶的

        【讨论】:

          【解决方案7】:

          如果它真的是一个随机数生成器,那么数字生成代码/状态可能会放置在类本地静态生成器中。这样,您的对象就不会发生变异,并且该方法可能会保持 const。

          【讨论】:

          • 这不是一个随机数生成器,我只需要一个 SO 示例。不过还是谢谢
          猜你喜欢
          • 2019-07-09
          • 2019-11-20
          • 2010-09-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多