What can a 'const' method change?
C++ methods allow a const
qualifier to indicate that the object is not changed by the method. 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开发者_JAVA技巧 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.
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.
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
.
There are two aspects to this question:
- what does
const
mean to the compiler? - 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.
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
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 const
ness, 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.
精彩评论