【问题标题】:Invoking a nonconst method on a member from a const method从 const 方法对成员调用 nonconst 方法
【发布时间】:2011-12-19 03:23:24
【问题描述】:

我很惊讶在“const”中发现了这个“漏洞”:

#include <stdio.h>

class A
{
  int r ;
public:
  A():r(0){}

  void nonconst()
  {
    puts( "I am in ur nonconst method" ) ;
    r++;
  }
} ;

class B
{
  A a ;
  A* aPtr ;

public:
  B(){ aPtr = new A() ; }

  void go() const
  {
    //a.nonconst() ;      // illegal
    aPtr->nonconst() ;  //legal
  }
} ;

int main()
{
  B b ;
  b.go() ;
}

所以基本上从const 方法B::go(),如果A 类型的对象被指针引用,您可以调用非const 成员函数(恰当地命名为nonconst())。

这是为什么呢?似乎是一个问题(它在我的代码中,我在其中找到它。)

【问题讨论】:

  • 这是相当出乎意料的。我在 Mac 上通过 g++ 4.2.1 运行它,并编译了代码(令我惊讶的是)。我很想知道这个问题的答案。
  • 这种行为在您第一次偶然发现时通常会令人惊讶。前段时间,我问this question 是否有将常量传播到指针对象的解决方案。

标签: c++ pointers constants const-correctness


【解决方案1】:

B 类型的对象是 const 时,它的所有成员都是 const,这意味着它的两个成员在 B::go() 的持续时间内有效

A const a;
A * const aPtr;

第一个是A类型的常量对象,你只能在其上调用const成员函数。然而,第二个是指向非常量A 的常量指针。您不能在函数B::go() 中合法地说出aPtr = &lt;anything&gt;,因为这会修改aPtr,这是不变的。

指向常量A 的指针将被声明为A const* aPtrconst A* aPtr,这将使调用非常量A::nonconst() 非法。

【讨论】:

  • 啊,非常聪明的答案。迂腐的。
【解决方案2】:

对象的“常量性”通过指针扩展到其他对象。在您的示例中,const 部分是整个对象 a,或 指针 aPtr。因为aPtrA * 而不是const A *,所以您可以调用非常量方法。

如果你改变了

A* aPtr ;

const A* aPtr ;

那么您将无法拨打aPtr-&gt;nonconst()

【讨论】:

  • Hmm.. 如果您需要使用它的非常量设施,这将使对象 A 几乎无用。我认为标记方法const 是不更改对象状态信息的合同...我认为所有 成员都应该标记const,甚至是ptrs!我有一个 dirty 位,每当调用非常量方法时都会设置它。但是现在,即使是一些const 方法也应该设置脏位!真是个惊喜。
  • 当一个对象是const时,它的所有成员也是const。您不能更改 aPtrconst 方法中指向的内容。但是,您当前的对象是 const 不会影响任何 other 对象的 const-ness。
  • @bobobobo "我认为所有成员都应该被标记为 const" 是的,他们当然是。希望这不会使其他对象成为常量。
【解决方案3】:

const的语言定义

我很惊讶在“const”中发现了这个“漏洞”:

没有。

const统一应用于所有类成员:在 C 类的 const 成员函数中,this 的类型为 const C *,因此对于成员 C::mem 声明输入T:

class C {
// ...
    T mem;
};

this-&gt;mem 的类型为 const T

请带type来辨别T声明的类型是什么,以及所有成员对应的const限定类型。

似乎是个问题(它在我的代码中,我发现它的地方。)

仅仅因为规则的系统应用没有达到你的预期,并不意味着规则有问题,这意味着你的预期有问题。

如果const 用于不同类型,您应该写下您的期望以查看您期望的非统一应用程序。

当你编程时,你必须逻辑推理。您应该推断事物,而不是在没有合乎逻辑的理由时期望它们。

正确使用const

这是为什么呢?

你的类被称为AB,很难理解什么是逻辑状态,什么不是。 ;) 你问了一个“道德”问题(不仅仅是关于合法/非法 C++ 程序的问题),而你的代码片段没有“道德”价值。如果您真的发布相关代码,我们可能会对此做出一些“道德”判断。

逻辑状态

您应该声明const 不会改变它所应用的对象的“逻辑状态”的函数。

这意味着你必须定义你的类实例的“逻辑状态”是什么:这是一个抽象概念,只有你可以定义它,因为它是一个高级概念。 “逻辑状态”与您的班级应该解决的问题有关。

然后您可以辨别哪些变量对逻辑状态有贡献:*(b.aPtr) 是否对b 的逻辑状态有贡献?

密切相关的问题

你知道拷贝构造函数吗?

关于复制赋值运算符?

关于析构函数?

【讨论】:

  • 真的,如果反对者可以添加某种解释,那将会有所帮助。
猜你喜欢
  • 2020-03-12
  • 2012-01-09
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-24
相关资源
最近更新 更多