In C, constants are often specified in programs using #define . The #define is essentially a macro expansion facility, for example, with the definition:
#define PI 3.14159265358979323846
the preprocessor will substitute 3.14159265358979323846 wherever PI is encountered in the source file. C++ allows any variable to be declared a constant by adding the const keyword to the declaration. For the PI constant above, we would write:
const double PI = 3.14159265358979323846;
A const object may be initialized, but its value may never change. The fact that an object will never change allows the compiler to ensure that constant data is not modified and to generate more efficient code. Since each const element also has an associated type, the compiler can also do more explicit type checking.
A very powerful use of const is found when it is combined with pointers. By declaring a ``pointer to const'', the pointer cannot be used to change the pointed-to object. As an example, consider:
int i = 10;
const int *pi = &i;
*pi = 15;
// Not allowed! pi is a const pointer!
It is not possible to change the value of i through the pointer because *pi is constant. A pointer used in this way can be thought of as a read-only pointer; the pointer can be used to read the data to which it points, but the data cannot be changed via the pointer. Read-only pointers are often used by class member functions to return a pointer to private data stored within the class. The pointer allows the user to read, but not change, the private data.
Unfortunately, the user can still modify the data pointed at by the read-only pointer by using a type cast. This is called ``casting away the const-ness''. Using the above example, we can still change the value of i like this:
// Cast away the constness of the pi pointer and modify i
*((int*) pi) = 15;
By returning a const pointer we are telling users to keep their hands off of internal data. The data can still be modified, but only with extra work (the type cast). So, in most cases users will realize they are not to modify that data, but can do so at their own risk.
There are two ways to add the const keyword to a pointer declaration. Above, when const comes before the * , what the pointer points to is constant. It is not possible to change the variable that is pointed to by the pointer. When when const comes after the *, like this:
int i = 10;
int j = 11;
int* const ptr = &i;
// Pointer initialized to point to i
the pointer itself becomes constant. This means that the pointer cannont be changed to point to some other variable after it has been initialized. In the above example, the pointer ptr must always point at the variable i. So, statements such as:
ptr = &j;
// Not allowed, since the pointer is const!
are not allowed and are caught by the compiler. However, it is possible to modify the variable that the pointer points to:
*ptr = 15;
// This is ok, what is pointed at is not const
If we want to prevent modification of what the pointer points to and prevent the value of the pointer from being changed, we must provide a const on both sides of the * like this:
const int * const ptr = &i;
Remember that adding const to a declaration simply invokes extra compile time type checking; it does not cause the compiler to generate any extra code. Another advantage of using the const mechanism is that the C++ construct will be available to a symbolic debugger, while the preprocessing symbols generally are not.
No comments:
Post a Comment