Re: How to define a const and initialize it?
From: Karl Heinz Buchegger (kbuchegg_at_gascad.at)
Date: 09/15/04
- Next message: bla abla: "Re: dont understand looping problem"
- Previous message: Tabrez Iqbal: "Re: Tips on gaining proficiency in C"
- In reply to: ranjeet: "Re: How to define a const and initialize it?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Wed, 15 Sep 2004 16:51:56 +0200
ranjeet wrote:
>
> Can you tell me one thing i can do this by making a macro also
> #deifne MYCONST 0x97
Yes, you could
>
> now if i use this macro.h in all the source file then it will
> do the same work as const int MYCONST will do....
>
> So i am bit puzzled about this issue ...
> that why we need the const key word..????
const has other usages also.
> when i can do the same whith the macros......
Well. Yes. But the thing is that macro substitution takes
place before the compiler even sees your code. So the actual
C++ compiler isn't even aware of its existence.
If you do it by a macro then a simple text substitution is taking
place. If you use a const, then that thing actually has a type
and the compiler can use that type.
To quote Scott Meyers
*********************
<Quote>
Item 1: Prefer const and inline to #define.
This Item might better be called "prefer the compiler to the preprocessor," because #define is often
treated as if it's not part of the language per se. That's one of its problems. When you do
something
like this,
#define ASPECT_RATIO 1.653
the symbolic name ASPECT_RATIO may never be seen by compilers; it may be removed by the preprocessor
before the source code ever gets to a compiler. As a result, the name ASPECT_RATIO may not get
entered
into the symbol table. This can be confusing if you get an error during compilation involving the
use
of the constant, because the error message may refer to 1.653, not ASPECT_RATIO. If ASPECT_RATIO was
defined in a header file you didn't write, you'd then have no idea where that 1.653 came from, and
you'd probably waste time tracking it down. This problem can also crop up in a symbolic debugger,
because, again, the name you're programming with may not be in the symbol table.
The solution to this sorry scenario is simple and succinct. Instead of using a preprocessor macro,
define a constant:
const double ASPECT_RATIO = 1.653;
This approach works like a charm. There are two special cases worth mentioning, however.
First, things can get a bit tricky when defining constant pointers. Because constant definitions
are typically put in header files (where many different source files will include them), it's
important that the pointer be declared const, usually in addition to what the pointer points to.
To define a constant char*-based string in a header file, for example, you have to write
const twice:
const char * const authorName = "Scott Meyers";
For a discussion of the meanings and uses of const, especially in conjunction with pointers, see
Item 21.
Second, it's often convenient to define class-specific constants, and that calls for a slightly
different tack. To limit the scope of a constant to a class, you must make it a member, and to
ensure
there's at most one copy of the constant, you must make it a static member:
class GamePlayer {
private:
static const int NUM_TURNS = 5; // constant declaration
int scores[NUM_TURNS]; // use of constant
...
};
There's a minor wrinkle, however, which is that what you see above is a declaration for NUM_TURNS,
not a definition. You must still define static class members in an implementation file:
const int GamePlayer::NUM_TURNS; // mandatory definition;
// goes in class impl. file
There's no need to lose sleep worrying about this detail. If you forget the definition, your linker
should remind you.
Older compilers may not accept this syntax, because it used to be illegal to provide an initial
value
for a static class member at its point of declaration. Furthermore, in-class initialization is
allowed
only for integral types (e.g., ints, bools, chars, etc.), and only for constants. In cases where the
above syntax can't be used, you put the initial value at the point of definition:
class EngineeringConstants { // this goes in the class
private: // header file
static const double FUDGE_FACTOR;
...
};
// this goes in the class implementation file
const double EngineeringConstants::FUDGE_FACTOR = 1.35;
This is all you need almost all the time. The only exception is when you need the value of a class
constant
during compilation of the class, such as in the declaration of the array GamePlayer::scores above
(where
compilers insist on knowing the size of the array during compilation). Then the accepted way to
compensate
for compilers that (incorrectly) forbid the in-class specification of initial values for integral
class
constants is to use what is affectionately known as "the enum hack." This technique takes advantage
of the
fact that the values of an enumerated type can be used where ints are expected, so GamePlayer could
just as
well have been defined like this:
class GamePlayer {
private:
enum { NUM_TURNS = 5 }; // "the enum hack" — makes
// NUM_TURNS a symbolic name
// for 5
int scores[NUM_TURNS]; // fine
...
};
Unless you're dealing with compilers of primarily historical interest (i.e., those written before
1995), you
shouldn't have to use the enum hack. Still, it's worth knowing what it looks like, because it's not
uncommon
to encounter it in code dating back to those early, simpler times.
Getting back to the preprocessor, another common (mis)use of the #define directive is using it to
implement
macros that look like functions but that don't incur the overhead of a function call. The canonical
example
is computing the maximum of two values:
#define max(a,b) ((a) > (b) ? (a) : (b))
This little number has so many drawbacks, just thinking about them is painful. You're better off
playing in
the freeway during rush hour.
Whenever you write a macro like this, you have to remember to parenthesize all the arguments when
you write
the macro body; otherwise you can run into trouble when somebody calls the macro with an expression.
But even
if you get that right, look at the weird things that can happen:
int a = 5, b = 0;
max(++a, b); // a is incremented twice
max(++a, b+10); // a is incremented once
Here, what happens to a inside max depends on what it is being compared with!
Fortunately, you don't need to put up with this nonsense. You can get all the efficiency of a macro
plus all
the predictable behavior and type-safety of a regular function by using an inline function (see Item
33):
inline int max(int a, int b) { return a > b ? a : b; }
Now this isn't quite the same as the macro above, because this version of max can only be called
with ints,
but a template fixes that problem quite nicely:
template<class T>
inline const T& max(const T& a, const T& b)
{ return a > b ? a : b; }
This template generates a whole family of functions, each of which takes two objects convertible to
the same
type and returns a reference to (a constant version of) the greater of the two objects. Because you
don't know
what the type T will be, you pass and return by reference for efficiency (see Item 22).
By the way, before you consider writing templates for commonly useful functions like max, check the
standard
library (see Item 49) to see if they already exist. In the case of max, you'll be pleasantly
surprised to
find that you can rest on others' laurels: max is part of the standard C++ library.
Given the availability of consts and inlines, your need for the preprocessor is reduced, but it's
not completely
eliminated. The day is far from near when you can abandon #include, and #ifdef/#ifndef continue to
play important
roles in controlling compilation. It's not yet time to retire the preprocessor, but you should
definitely plan to
start giving it longer and more frequent vacations.
</Quote>
Scott Meyers
Effective C++
Definitly a *must* book for any serious C++ programmer
-- Karl Heinz Buchegger kbuchegg@gascad.at
- Next message: bla abla: "Re: dont understand looping problem"
- Previous message: Tabrez Iqbal: "Re: Tips on gaining proficiency in C"
- In reply to: ranjeet: "Re: How to define a const and initialize it?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|