const 成员函数可以改变什么?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在不显式放弃常量的情况下,
const
成员函数可以更改:可变
数据成员,以及const
访问权限的任何数据,无论该数据是否可访问:这些限制也适用于数据成员和基数的操作(在面向对象的意义上)。更明确地说,当
*this
的数据成员或基类属于class
/struct 时,
/const
成员函数对它们进行操作union
类型,只能调用其const
成员函数(如果有),并且只能写入其mutable
数据成员(如果有的话)。(const 成员函数还可以更改任何非 const 局部变量和按值参数,但我知道这不是您感兴趣的)。
const
数据成员可以调用其他const
成员函数,这些函数也具有相同的功能和限制。这意味着指针不能(轻易/意外地)改变。它不意味着所指向的内存无法更改。
您偶然发现的是 const 函数更改对象概念上拥有的指向或引用数据的逻辑错误。正如您所发现的,编译器不会强制执行您可能想要或期望的
const
正确性。这有点危险,但意味着不需要显式删除指向其他对象的指针/引用的常量,这些对象可能会作为 const 函数的副作用而更改 。例如,日志记录对象。 (通常,此类对象在逻辑上并不由其const
函数对其进行操作的对象“拥有”。)关键点是编译器无法可靠地区分对象拥有的逻辑所有权类型超过指向的数据,因此它必须以一种或另一种方式进行猜测,并允许程序员重写或不受 const 保护。 C++ 放弃了保护。有趣的是,我听说 Walter Bright 的 D 语言翻转了这个默认值,在
const
函数中默认使指向数据const
。这对我来说似乎更安全,尽管很难想象人们最终需要明确放弃常量以允许想要的副作用的频率,以及这是否会让人感到令人满意的精确或烦人的冗长。Without explicitly casting away constness, a
const
member function can change:mutable
data members, andconst
access to, irrespective of whether that data's accessible: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 ofclass
/struct
/union
type, can only call theirconst
member functions (if any), and can only write to theirmutable
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 otherconst
member functions, which will have these same abilities and restrictions.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 theconst
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 theconst
function. For example, a logging object. (Typically, such objects are not logically "owned" by the object whoseconst
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 byconst
-ness. C++ forgoes the protection.Interesting, I've heard Walter Bright's D language flips this default, making pointed-to data
const
by default inconst
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.最简单地说,这意味着 const 成员函数中
this
的类型是const T *
,其中T
是您的类,而在非限定函数中它是T *
。您的方法
set
不会更改data
,因此可以将其限定为 const。换句话说,myclass::data
作为this->data
进行访问,并且类型为int * const
。Most succinctly, it means that the type of
this
isconst T *
inside const member functions, whereT
is your class, while in unqualified functions it isT *
.Your method
set
does not changedata
, so it can be qualified as const. In other words,myclass::data
is accessed asthis->data
and is of typeint * const
.这个问题有两个方面:
const
对编译器意味着什么?问题1
第一个问题很简单。编译器验证没有数据成员被修改(除非它们被限定为
可变
)。它递归地验证这一点:对于任何用户定义的类型,它检查是否没有调用非常量方法。对于内置类型,它会验证它们是否未被分配。指针的转换是从
T*
到T*const
(const 指针),而不是const T*
(指向 const 的指针)。这意味着编译器不会验证指向的对象是否未被修改。显然,这引出了问题2。问题2
当编译器不验证时,
const
如何应用?它意味着对您的应用程序意味着什么。这通常称为逻辑常量。何时使用关于逻辑常量的 const 是 服从 辩论。There are two aspects to this question:
const
mean to the compiler?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*
toT*const
(const pointer), notconst 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 useconst
with respect to logical const-ness is subject to debate.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).
const 基本上可以防止更改函数内的类实例成员的值。这对于更清晰的界面很有用,但例如在使用继承时会造成限制。有时有点欺骗性(或者实际上有很多欺骗性),如您发布的示例所示。
const
最适合Get
函数,在该函数中,调用者显然正在读取值并且无意更改对象状态。在这种情况下,您可能希望限制继承的实现并遵守常量,以避免使用多态性时出现混乱和隐藏的错误。例如
将 A 更改为:
解决问题。
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 forGet
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 toconst
ness, to avoid confusion and hidden bugs when using polymorphism.For example
changing A to:
solves the problem.