const 成员函数可以改变什么?

发布于 2024-11-26 17:06:45 字数 422 浏览 2 评论 0原文

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,但它确实会更改数组的内容。

C++ methods allow a const qualifier to indicate that the object is not changed by the member function. But what does that mean? Eg. if the instance variables are pointers, does it mean that the pointers are not changed, or also that the memory to which they point is not changed?

Concretely, here is a minimal example class

class myclass {
  int * data;

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

  ~myclass() {
    delete [] data;
  }

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

Does the method set correctly qualify as const? It does not change the member variable data, but it sure does change the content of the array.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鼻尖触碰 2024-12-03 17:06:45

“const”方法可以改变什么?

在不显式放弃常量的情况下,const 成员函数可以更改:

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

这些限制也适用于数据成员和基数的操作(在面向对象的意义上)。更明确地说,当 *this 的数据成员或基类属于 class/struct 时,const 成员函数对它们进行操作/union 类型,只能调用其 const 成员函数(如果有),并且只能写入其 mutable 数据成员(如果有的话)。

(const 成员函数还可以更改任何非 const 局部变量和按值参数,但我知道这不是您感兴趣的)。

const 数据成员可以调用其他 const 成员函数,这些函数也具有相同的功能和限制。

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

这意味着指针不能(轻易/意外地)改变。它意味着所指向的内存无法更改。

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

有趣的是,我听说 Walter Bright 的 D 语言翻转了这个默认值,在 const 函数中默认使指向数据 const 。这对我来说似乎更安全,尽管很难想象人们最终需要明确放弃常量以允许想要的副作用的频率,以及这是否会让人感到令人满意的精确或烦人的冗长。

What can a 'const' method change?

Without explicitly casting away constness, a const member function can change:

  • mutable data members, and
  • any data the class has non-const access to, irrespective of whether that data's accessible:
  • via member variables that are pointers or references,
  • via pointers or references passed as function arguments,
  • via pointers or references returned by functions,
  • directly in the namespace or class (for static members) containing it.

These restrictions apply to operations of data members and bases (in the OO sense) too. More explicitly, a const member function operating on *this's data members or bases, when they're of class/struct/union type, can only call their const member functions (if any), and can only write to their mutable data members (if any).

(A const member function can also change any non-const local variables and by-value parameters, but I know that's not what you're interested in).

const data members can call other const member functions, which will have these same abilities and restrictions.

Eg. if the instance variables are pointers, does it mean that the pointers are not changed, or also that the memory to which they point is not changed?

It means the pointers can't be (easily/accidentally) changed. It does not mean that the pointed-to memory can't be changed.

What you've stumbled on is the logical incorrectness of a const function changing pointed-to or referenced data conceptually owned by the object. As you've found, the compiler doesn't enforce the const correctness you may want or expect here. That's a bit dangerous, but means constness doesn't need to be explicitly removed for pointers/references to other objects which may be changed as a side-effect of the const function. For example, a logging object. (Typically, such objects are not logically "owned" by the object whose const function is operating on them.) The key point is that the compiler can't reliably distinguish the type of logical ownership an object has over pointed-to data, so it's got to guess one way or the other and allow the programmer to either override, or not be protected by const-ness. C++ forgoes the protection.

Interesting, I've heard Walter Bright's D language flips this default, making pointed-to data const by default in const functions. That seems safer to me, though it's hard to imagine how often one would end up needing to explicitly cast away constness to allow wanted side-effects, and whether that would feel satisfyingly precise or annoyingly verbose.

世俗缘 2024-12-03 17:06:45

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

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

Most succinctly, it means that the type of this is const T * inside const member functions, where T is your class, while in unqualified functions it is T *.

Your method set does not change data, so it can be qualified as const. In other words, myclass::data is accessed as this->data and is of type int * const.

死开点丶别碍眼 2024-12-03 17:06:45

这个问题有两个方面:

  1. const 对编译器意味着什么?
  2. 当编译器无法验证 const 时,它如何应用?

问题1

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

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

问题2

当编译器不验证时,const 如何应用?它意味着对您的应用程序意味着什么。这通常称为逻辑常量。何时使用关于逻辑常量的 const 是 服从 辩论

There are two aspects to this question:

  1. what does const mean to the compiler?
  2. how does const apply when it cannot be validated by the compiler?

Question 1

The first is rather simple. The compiler validates that no data members are modified (unless they are qualified as mutable). It validates this recursively: for any user-defined types, it checks that no non-const methods are invoked. For built-in types, it validates that they are not assigned.

The transformation for pointers is T* to T*const (const pointer), not const T* (pointer to const). This means that the compiler does not validate that the object pointed to is not modified. Obviously, this leads to question 2.

Question 2

How does const apply when not validate by the compiler? It means whatever it should mean to your application. This is usually referred to as logical const. When to use const with respect to logical const-ness is subject to debate.

自找没趣 2024-12-03 17:06:45

const 应用于方法时意味着:

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

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

const when applied to a method means:

This means that the state of the object will not be changed by the method.
This means any members that are part of the objects state can not be modified, nor can any functions that are not also const be called.

As this relates to pointers. It means the pointer (if it is part of the state) can not be changed. But the object the pointer points at is part of another object so that means you can call non cost methods on this object (as it is not part of the state of this object).

┾廆蒐ゝ 2024-12-03 17:06:45

const 基本上可以防止更改函数内的类实例成员的值。这对于更清晰的界面很有用,但例如在使用继承时会造成限制。有时有点欺骗性(或者实际上有很多欺骗性),如您发布的示例所示。

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

例如

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;};

解决问题。

const basically prevents changing the class instance members' values inside the function. This is useful for more clearer interface, but pose restrictions when using inheritance for example. It's sometimes a little bit deceiving (or a lot actually), as in the example you posted.

const would be most appropriate for Get functions, where it is obvious that the caller is reading a value and has no intentions of changing the object state. In this case you would want to limit the inherited implementations as well to adhere to constness, to avoid confusion and hidden bugs when using polymorphism.

For example

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

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

changing A to:

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

solves the problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文