【问题标题】:Const pointer argument to a method which delegates to removeAll()委托给 removeAll() 的方法的常量指针参数
【发布时间】:2010-08-31 22:08:03
【问题描述】:

考虑这样的方法:

void Parent::removeChild(Child *child)
{
    children.removeAll(child);
}

在这种情况下,由于 child 本身永远不会被修改,因此可以将其设为 const 指针。但由于 children 属于 QList 类型,removeAll() 采用对 non-const 指针的 const 引用。

推荐的处理方法是什么?跳过方法参数的常量或 const_cast 常量指针以适应 removeAll() 方法?

【问题讨论】:

  • 当您说“常量指针”时,您是指const Child * 还是Child * const?当您说“对非 const 指针的 const 引用”时,您的意思是 Child * const & 还是别的什么?存在固有的歧义,因为“const 指针”严格表示 T * const,但在随意使用时可能表示 const T *
  • 很抱歉给您带来了困惑。我的意思是参数的“指向 const Child 的指针”,而 removeAll() 将采用“对指向非 const child 的指针的 const 引用”。我总是忘记哪个语法是哪个。所以我说的显然不是指针值本身,而是指向的对象,孩子。
  • 我不清楚这一点。什么是 QList,它有什么作用,它来自哪里?
  • 好的,我查了一下,这是一个QList这个事实与指针是否为const无关。大概children 被声明为QList<Child *> 或类似的东西,这就是相关的。在这里显示children 的实际声明可以避免混淆。

标签: c++ const-correctness


【解决方案1】:

棘手的一个。您应该添加更多代码,但从 docs 开始,我假设您有一个 QList<Child*> 并且不能将其更改为 QList<const Child*>,因为您需要以非常量方式访问实际对象。

由于所有removeAll() 函数所做的就是删除列表中的条目并且它绝不会修改指向的 Child(它怎么可能,它对 Child 类一无所知)它会是安全的这里使用const_cast

【讨论】:

  • 现在这是我要求的:)
【解决方案2】:

如果您想说更改子列表不是更改父实例,那么只需将子列表设为mutable

但是,请确保它确实是您想要的 Parent 类的语义。如果孩子不是 Parent 状态的一部分(在您系统的语义中),那么它应该没问题。如果它是 Parent 实例状态的一部分,那么您应该保留一个非常量成员函数。

mutable 关键字用于那些不应将类的成员视为实例状态的例外情况,而只是附加信息。如果是您的情况,请使用它。

否则,让您的成员函数为非常量,因为它会修改父成员。

【讨论】:

  • 进一步了解@Billy 所说的,mutable 允许const 方法写入非const 数据。它不允许采用const T * 参数的方法将其转换为T *
  • "然后让子列表可变。"如果它是想要的语义,我建议它是可变的成员。事实是,此处所需的演员表表明,如果父类的成员 children(QList AFAIU)发生更改,则 Emil Eriksson 不希望将其视为“更改”。因此,要使他的函数为 const,他确实需要使该列表可变或假设更改列表实际上是更改父级。否则,这里的 const 强制转换是一个补丁,只会让类的用户不明显。
【解决方案3】:

看起来QList 被设计用于非指针。他们将很多 const 接口定义为 const T&,如果您的 QList 位于 Child 而不是 Child*,这将非常有用。

它可以很好地处理指针,但它不能为它们声明常量。我不建议将您的 QList 更改为 Child,除非复制成本低,您拥有复制 ctor、dtor、op=、op== 等的所有正确语义,并且您不介意在列表中保留副本而不是您传入的对象。您可以看到 int 或字符串如何按预期工作(removeAll 将是 const 正确的)。

如果 const 正确性对您很重要,请使用 const_cast。然后声明一个 const ref 并将其传入。

void Parent::removeChild(const Child *child)
{
    QList<Child*>::const_reference constRefToChild = const_cast<Child *> child;
    children.removeAll(constRefToChild);
}

这里的重点是,如果 removeAll 被更改为不接受 const,则会出现编译器错误。然后你就会知道 removeAll 并没有保留参数的常量性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    • 1970-01-01
    • 2014-02-24
    相关资源
    最近更新 更多