views:

152

answers:

6

Here is some code copied from Thinking in C++ Vol1 Chapter 10.

   #include <iostream>
   using namespace std;

   int x = 100;

   class WithStatic {
        static int x;
        static int y;
        public:
             void print() const {
             cout << "WithStatic::x = " << x << endl;
             cout << "WithStatic::y = " << y << endl;
           }
  };

what's the meaning of const for the function print()? Thanks!

+1  A: 

It's a guarantee that the function won't modify the object at all (i.e. it's a "read-only" function). EDIT: Apparently, the exception to that rule is if an object has mutable members; those can be changed by both const and non-const functions.

Also, I'm glad to see somebody else learning from TIC++. It's a great resource for beginners.

Maulrus
Not completely true, `mutable` members can be changed.
jweyrich
Oh, I wasn't aware of the `mutable` keyword. I'll change my answer.
Maulrus
`mutable` is rather a new development in C++.
Ben Voigt
A: 

the const means print() is not allowed to modify state variables not marked with volatile.

sreservoir
iirc, it's an optional compile-time check, so while you *can*, it's a really bad idea to try to modify stuff.
sreservoir
@sreservoir, while it is only a compile-time check, you can (read: don't because you promised you wouldn't) modify non-const members, if you use a const_cast to remove the const from the this pointer. Members marked as mutable may be modified regardless of const-ness of the member function.
Nathan Ernst
@sreservoir it's `mutable`, not `volatile`.
jweyrich
@Nathan Ernst: Are you sure that using `const_cast` to modify a `const` object is not undefined behaviour? It'll probably work on many systems but if it is undefined behaviour you can't rely on it working that way.
dreamlax
@dreamlax: It's undefined behavior if the object pointed to by `this` was created `const` (if it's a `const` global, it might even be in read-only memory). If somebody created a `const` pointer to a writable object and passed it to a function that used `const_cast`, things work pretty much normally (unless you did something else bad like aliased a `restrict` pointer).
Ben Voigt
volatile has nothing to do with this. mutable is the keyword you're looking for.
iconiK
@Ben Voigt: Thanks for the insight. There is no way to know for sure whether the object was created non-const or const, is there? If not, then using `const_cast` to modify member variables in a `const` method is a tad dangerous.
dreamlax
@dreamlax: True. The only legitimate purpose for `const_cast` is to pass a `const` pointer to a function whose contract is to not modify the object but failed to declare it as `const` (either because the function was written before `const` was standardized, or because the function conditionally modifies the parameter depending on other arguments).
Ben Voigt
+1  A: 

It means that it doesn't change any member variables of the class.

http://www.parashift.com/c++-faq-lite/const-correctness.html

dan04
+1  A: 

What it does is effectively make the this pointer be a const pointer to const instead of a const pointer to non-const. So, any time that you reference this in a const member function - either explicitly or implicitly - you're using a const pointer to const.

So, in the case of the class you have here, in any non-const function, the type of this is WithStatic const * while in the const functions, its type is const WithStatic * const.

Like with any pointer to const, you can't alter anything that it points to. So, you can't alter any of its member variables, and you can't call any of its non-const member functions.

Generally speaking, it's a good idea to make a member function be const if you can reasonably do so, because it guarantees that you're not going to alter the object's state, and you can call it with a const object.

It is possible for member variables to be altered if they're mutable or volatile, but those are more advanced topics that are probably better avoided until you're more familiar with the language. Certainly, you don't usually need to worry about them and shouldn't use them unless you need to. It's also possible to cast away the constness of the this pointer, at which point you could alter it, but IIRC, that's undefined behavior, and it's definitely generally considered a bad idea. So, there are instances where it's possible to alter an object's state within a const member function, but it's not normally possible and best avoided even when it is.

When you make a member function const, you're effectively promising that the object's state will not be changed by that function call (though there can obviously be side effects as evidenced by the fact that you can call functions like printf()).

Jonathan M Davis
No, `volatile` members can't be changed by const methods, only `mutable` ones. AFAIK, the only way to change non-mutable members is using `const_cast`.
jweyrich
Actually no, the type of this is: const WithStatic * (for non-const functions) and const WithStatic * const (for const functions). Pointer const goes after the asterisk.
iconiK
Okay. Pointer syntax fixed. This is why I hate C++ pointer syntax. It gets so messy. As for volatile. No, you can't change it within a const function, but it *can* change out from under you. So, it does fit in with the things that go against the const-ness of a const function, but no, a const function cannot itself change a volatile variable.
Jonathan M Davis
Pointer syntax not fixed. Try "in any non-const function, the type of `this` is `WithStatic * const`".
Ben Voigt
\*Sigh\*. Good catch. It was only half-fixed. Now it should be fully fixed. I guess that I was in too much of a hurry. It doesn't help that `const* T` is by far the most frequent way I use const with pointers. Pointer syntax is easy to mess up - especially if you're in a hurry and not actually compiling what you write. Thanks.
Jonathan M Davis
+2  A: 
dreamlax
+1 for near completeness.
jweyrich
+1  A: 

If a member function is declared "const", it means that the function will not modify the object's state. This:

  • Documents the fact that the function will not modify state (useful to other developers).
  • Allows the compiler to make optimizations, knowing that the result of other "const" functions will not have changed as a result of calling that function (which allows function calls to be taken out of loops).
  • Enables one to call the function when the object is passed by const reference, const pointer, etc.

For all the above reasons, one should, as a general rule of thumb, declare a function as "const" if it does not logically modify the state of the object. If the logical state of the object changes, then don't use "const". As an aside, there are cases where the actual state changes but the logical state does not (e.g. caching), in which case one should still mark the function as "const", but one needs to use the "mutable" keyword with the caching variables in order to tell the compiler that modifying them actually doesn't change the logical state.

Michael Aaron Safyan