Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

15 Understanding

Constants

Technique

Save Time By

Exploring the uses of constants

Defining constants

Implementing constants

Using the const keyword

Pity the poor, misunderstood C++ constant — there are so very many ways to use it, yet so few of them are really understood. By using the constant (or const statement) construct in your code, your

applications can be made safer, more readable, and more efficient. Yet, programmers are often so overwhelmed by the incredible number of different ways in which they can use constants that they simply avoid the construct completely, allowing the compiler to pick and choose what can change and what cannot in the application. A word to the wise: Allowing the compiler to make choices for you is very rarely a good idea.

Constants provide a way to self-document your code, as well as a simple way to locate all of the definitions of values in your program. By utilizing constants for your data values, you can make quick, easy, simultaneous changes across the scope of your application. In addition, you can enforce what does and does not change in the methods and functions of your application by using the const keyword.

In this technique I explore the various possibilities for working with constants in C++ and what they mean to you as an application developer.

Defining Constants

To best understand how constants work and how you can utilize them in your application, the following steps show you a simple example of

defining various kinds of constants. We will be creating a file that contains constants for use as whole numbers, floating point numbers, and character strings. You will see how a constant can directly replace a #define value, as well as how the compiler can be used to do type-safe checking of constant assignments.

1. In the code editor of your choice, create a new file to hold the code for the implementation of the source file.

In this example, the file is named ch15.cpp, although you can use whatever you choose.

78 Technique 15: Understanding Constants

2. Type the code from Listing 15-1 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 15-1: THE CONSTANTS AND THEIR DEFINITIONS

#include <stdio.h> #include <stdlib.h>

//This is a constant value that can be used

//in place of a #define value

const int MaxValues = 100;

//Unlike the #define, you can use a const

//for typesafe constants

const char *StringName = “Matt Telles”; const double Cost = 100.35;

const long MaxLong = 1000000;

You can define constants of pretty much any shape or size. Constants can be numbers, strings, characters, or floats. More importantly, the compiler will check for type safety when you assign a constant to another value. For example, you’re permitted to assign string values to string constants, like this:

string myString = StringName;

You are not, however, permitted to assign MaxLong values to integers, which would look like this:

int iVal = MaxLong; // The compiler will complain.

3. Save the source-code file.

Of course (so far), all adding the constants has really done is give us another way to replace the #define statement in our application. The real meat of the C++ constant is giving the compiler directives in your functions and classes, as I show you in the next section.

Implementing Constant

Variables

The const statement can also be used to tell the compiler that something is not permitted to change, as we will see in this simple technique that relies on another facet of the const keyword. Follow these steps to see how it all works:

1. Append the code from Listing 15-2 to your source-code file.

LISTING15-2: A FUNCTION WITH AN IMMUTABLE ARGUMENT

//Functions can take constant arguments, allowing them

//to guarantee that values don’t change.

int func( const int& x )

{

//We can do this int z = x;

//We cannot do this. Compile Error:

//x = 10;

1

return x;

 

}

This function accepts a single argument of type const int reference. The const modifier indicates to the compiler that the input argument cannot be modified. If you were to uncomment the line marked 1, you would see the compiler generate an error telling you that you cannot modify a constant reference.

This example looks at a function that accepts a single-integer argument, the constant x. We are informing both the user of the function and the compiler that this function will never change the value of that argument, even if it is passed in by reference. This information is very important to the compiler; with this knowledge it can optimize your function so that it does not have to pop the

 

Implementing Constant Variables

79

value back off the stack and insure that the mem-

because the compiler would never allow you to

ory location that it is using will not change. This

write this:

 

is possible because this value can be thrown

 

 

away after the function is done; after all, it could

int myVal = func(3);

 

not possibly have changed.

When you define the input argument as a con-

 

Proper use of the const modifier allows the

stant, however, the compiler is now aware that

the actual memory location that’s holding your

compiler to generate closer-to-optimal code

and generate better warnings, so you can

value (in this case, 3) will not change, and it will

write better applications and have fewer errors

allow you to pass in the integer value without

to fix in the debugging phase.

first assigning it to anything. This arrangement

 

saves a few CPU cycles and some memory — and

Furthermore, because we know that the input is

you don’t have to write some silly code that

 

doesn’t really do anything.

 

a constant, we can pass in values that are con-

 

2. Using your code editor, append the code from

stant. For example, if the reference was not a

constant, you’d have to write this:

Listing 15-3 to your source-code file.

 

int x = 3;

This technique illustrates how you can use the

int myVal = func( x );

const keyword within a class to accomplish the

 

 

same things that it does outside of a class listing.

LISTING 15-3: CONSTANTS IN CLASSES

 

 

 

// Classes can have constants in them

 

const int MaxEntries = 10;

 

class Foo

 

{

 

int entries[ MaxEntries ];

 

public:

//You can pass in constant references to arguments Foo()

{

}

Foo( const Foo& aCopy )

{

for ( int i=0; i<MaxEntries; ++i ) entries[i] = aCopy.entries[i];

}

//You can return constant references from methods const int * getEntries()

{

return &entries[0];

}

//You can indicate that a method will NOT change

//anything in the object

int getEntry( int index ) const

{

return entries[index];

(continued)

80 Technique 15: Understanding Constants

LISTING 15-3 (continued)

}

//The two can be combined to say that the return value

//cannot be changed and the object will not change const int& getAConstEntry( int index ) const

{

return entries[index];

}

};

3. Save the source-code file and close the code editor.

As you can see, the const construct is quite versatile. It can be used to indicate a value that is used to replace a number in your code. It can be used to indicate a return value that cannot be changed. It can indicate that a class method accepts an argument that it doesn’t change, such as the Copy constructor. Can you imagine writing a Copy constructor that changed the object it copied? That would be a little strange to say the least. Imagine writing something like this:

Foo f1 = f;

Then imagine having the f object change out from under you — talk about your basic debugging nightmare. For this reason, it’s customary to use a const reference, indicating that you won’t change the object being copied. In the same manner, we can pass in values to methods and assure the user that they won’t be copied (as in the func function we looked at earlier in Listing 15-2).

Of course, if you can take an input value and assure the user that you will not change it, then the quid pro quo argument is that you must be able to give someone back a value and make sure that they don’t change it. This is called returning a const reference. For example, if you have an internal variable, you could create a reference method that gave it back, but only in a read-only fashion. That is what the getEntries method does in Listing 15-3. It returns a const pointer that makes sure that the user doesn’t change anything in the program that calls the object.

Finally, you can tell the user that the method you are calling will never change the object. To do so, you simply append the const keyword at the end of the method, which allows your method to be called on const objects. Doing so also allows the compiler to avoid the overhead of having to make copies of objects and such. If the object cannot be changed via the method, there is no reason to worry about making the memory location static.

Testing the Constant Application

After you create the class, you should create a test driver that not only ensures that your code is correct, but also shows people how to use your code.

1. In the code editor of your choice, open the existing file to hold the code for your test program.

In this example, I named the test program ch15.cpp.

The next step (for wise programmers, and you know who you are) is to add a simple test driver to the source file so you can take a look at how all this plays out.

2. Type the code from Listing 15-4 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 15-4: THE TEST DRIVER FOR CONSTS

int main(int argc, char **argv)

{

Foo f;