'const'方法可以改变什么?

时间:2011-07-28 00:06:38

标签: c++

C ++方法允许const限定符指示该方法未更改对象。但是,这是什么意思?例如。如果实例变量是指针,它是否意味着指针没有改变,或者它们指向的内存没有改变?

具体来说,这是一个最小的示例类

class myclass {
  int * data;

  myclass() {
    data = new int[10];
  }

  ~myclass() {
    delete [] data;
  }

  void set(const int index) const {
    data[index] = 1;
  }
};

方法set是否正确符合const的条件?它不会更改成员变量data,但确实会更改数组的内容。

5 个答案:

答案 0 :(得分:21)

  

'const'方法有什么变化?

如果没有明确地抛弃constness,const方法可以改变:

  • mutable数据成员和
  • 该类具有非const访问权限的任何数据,无论该数据是否可访问:
    • 通过指针或引用的成员变量,
    • 通过作为函数参数传递的指针或引用,
    • 通过函数返回的指针或引用,
    • 直接在包含它的命名空间或类(用于静态)中。

对于class / struct / union类型的成员,它依赖于其成员函数的常量来确定应允许哪些操作。 (它也可以改变任何非const局部变量和值的参数,但我知道这不是你感兴趣的东西。)

它可以调用具有相同能力和限制的其他const方法。

  

EG。如果实例变量是指针,它是否意味着指针没有改变,或者它们指向的内存没有改变?

这意味着指针不能(容易/偶然)改变。 意味着无法更改指向的内存。

你偶然发现的是const函数的逻辑错误,它改变了对象概念上所拥有的指向或引用的数据。正如您所发现的,编译器不会强制执行您可能想要或期望的const正确性。这有点危险,但意味着 constness不需要显式删除指针/对其他对象的引用,这些对象可能会被更改为const函数的副作用。例如,日志记录对象。 (通常,这些对象在其const函数对其进行操作的对象上不会在逻辑上“拥有”。)关键点是编译器无法可靠地区分对象具有的逻辑所有权的类型 - 对数据,所以它必须猜测这种或那种方式,并允许程序员覆盖,或不受const - ness的保护。 C ++放弃了保护。

有趣的是,我听说Walter Bright的D语言翻转了这个默认值,默认情况下在const函数中生成了有针对性的数据const。这对我来说似乎更安全,但很难想象人们最终需要多久才能明确地抛弃常量以允许想要的副作用,以及是否会感到令人满意的精确或烦人的冗长。

答案 1 :(得分:15)

最简洁的是,它意味着this的类型在const成员函数中是const T *,其中T是您的类,而在非限定函数中它是T *

您的方法set不会更改data,因此可以将其限定为const。换句话说,myclass::data的访问权限为this->data,类型为int * const

答案 2 :(得分:6)

这个问题有两个方面:

  1. const对编译器意味着什么?
  2. 编译器无法验证时const如何应用?
  3. 问题1

    第一个很简单。编译器验证没有修改任何数据成员(除非它们被限定为mutable)。它以递归方式验证:对于任何用户定义的类型,它会检查是否没有调用非const方法。对于内置类型,它验证它们未被分配。

    指针的转换是T*T*const(const指针),而不是const T*(指向const的指针)。这意味着编译器不会验证指向的对象是否未被修改。显然,这导致问题2。

    问题2

    编译器未验证时const如何应用?它意味着它对您的应用程序应该意味着什么。这通常称为逻辑const。何时使用const关于逻辑常数subjectdebate

答案 3 :(得分:0)

const应用于方法时意味着:

这意味着该方法不会改变对象的state 这意味着不能修改任何属于对象状态的成员,也不能调用任何不是const的函数。

因为这与指针有关。这意味着指针(如果它是状态的一部分)无法更改。但是指针指向的对象是另一个对象的一部分,这意味着你可以在这个对象上调用非成本方法(因为它不是该对象状态的一部分)。

答案 4 :(得分:-1)

const基本上阻止了在函数内部更改类实例成员的值。这对于更清晰的界面很有用,但在使用继承时会造成限制。它有时会有点欺骗(或实际上很多),就像你发布的例子一样。

const最适合Get函数,显然调用者正在读取值并且无意改变对象状态。在这种情况下,您可能希望限制继承的实现以遵守const,以避免在使用多态时出现混淆和隐藏错误。

例如

class A{
     int i;
   public:
     virtual int GetI() {return i;};
}

class B : public A{
   public:
     int GetI() { i = i*2; return i;}; // undesirable
}

将A更改为:

virtual int GetI() const {return i;};

解决了这个问题。