const objects & member functions
Class member functions can be made
const. What does this mean? To understand, you must first grasp the
concept of const objects.
A const object is defined the same
for a user-defined type as a built-in type. For example:
const int i = 1;
const blob b(2);
Here, b is a const object
of type blob. Its constructor is called with an argument of two. For the
compiler to enforce constness, it must ensure that no data members of the
object are changed during the object’s lifetime. It can easily ensure that
no public data is modified, but how is it to know which member functions will
change the data and which ones are “safe” for a const
object?
If you declare a member function
const, you tell the compiler the function can be called for a
const object. A member function that is not specifically declared
const is treated as one that will modify data members in an object, and
the compiler will not allow you to call it for a const
object.
It doesn’t stop there, however.
Just claiming a member function is const doesn’t guarantee
it will act that way, so the compiler forces you to reiterate the const
specification when defining the function. (The const becomes part of the
function signature, so both the compiler and linker check for constness.)
Then it enforces constness during the function definition by issuing an
error message if you try to change any members of the object or call a
non-const member function. Thus, any member function you declare
const is guaranteed to behave that way in the
definition.
To understand the syntax for declaring
const member functions, first notice that preceding the function
declaration with const means the return value is const, so that
doesn’t produce the desired results. Instead, you must place the
const specifier after the argument list. For
example,
//: C08:ConstMember.cpp
class X {
int i;
public:
X(int ii);
int f() const;
};
X::X(int ii) : i(ii) {}
int X::f() const { return i; }
int main() {
X x1(10);
const X x2(20);
x1.f();
x2.f();
} ///:~
Note that the const keyword must
be repeated in the definition or the compiler sees it as a different function.
Since f( ) is a const member function, if it attempts to
change i in any way or to call another member function that is not
const, the compiler flags it as an error.
You can see that a const member
function is safe to call with both const and non-const objects.
Thus, you could think of it as the most general form of a member function (and
because of this, it is unfortunate that member functions do not automatically
default to const). Any function that doesn’t modify member data
should be declared as const, so it can be used with const
objects.
Here’s an example that contrasts a
const and non-const member function:
//: C08:Quoter.cpp
// Random quote selection
#include <iostream>
#include <cstdlib> // Random number generator
#include <ctime> // To seed random generator
using namespace std;
class Quoter {
int lastquote;
public:
Quoter();
int lastQuote() const;
const char* quote();
};
Quoter::Quoter(){
lastquote = -1;
srand(time(0)); // Seed random number generator
}
int Quoter::lastQuote() const {
return lastquote;
}
const char* Quoter::quote() {
static const char* quotes[] = {
"Are we having fun yet?",
"Doctors always know best",
"Is it ... Atomic?",
"Fear is obscene",
"There is no scientific evidence "
"to support the idea "
"that life is serious",
"Things that make us happy, make us wise",
};
const int qsize = sizeof quotes/sizeof *quotes;
int qnum = rand() % qsize;
while(lastquote >= 0 && qnum == lastquote)
qnum = rand() % qsize;
return quotes[lastquote = qnum];
}
int main() {
Quoter q;
const Quoter cq;
cq.lastQuote(); // OK
//! cq.quote(); // Not OK; non const function
for(int i = 0; i < 20; i++)
cout << q.quote() << endl;
} ///:~
Neither constructors nor destructors can
be const member functions because they virtually always perform some
modification on the object during initialization and cleanup. The
quote( ) member function also cannot be const because it
modifies the data member lastquote (see the return statement).
However, lastQuote( ) makes no modifications, and so it can be
const and can be safely called for the const object
cq.