UMBC CMSC202, Computer Science II, Fall 1998,
Sections 0101, 0102, 0103, 0104
4. C++ Declarations & Definitions
Thursday September 10, 1998
Assigned Reading: 3.1-3.5
Handouts (available on-line):
Programs from this lecture.
- Actually, we discussed C++ Definitions and Declarations. To
understand the difference between a "definition" and a "declaration" we
should consider two concepts: scoping and allocation. When a variable
or a function is declared, this deals with a scoping issue. The
compiler needs to know if what the identifier is (variable or function?)
and about the types involved. When a variable is defined, allocation
issues are also involved. Where is the variable stored? what is the
initial value? A function prototype is an example of a declaration that
is not a definition. A function's definition is just its implementation.
An identifier can be declared many times, but defined only once.
- C and C++ use lexical scoping. The scope of an identifier (name of
variable, function, type, etc.) is the places in the program where the
identifier makes sense to the compiler. "Lexical" scoping means that you
can determine the scope of an identifier simply by scanning the text of the
program (e.g., how the blocks are nested) and you do not have to consider
what the program does when you run it (e.g., which functions call other
functions and in what order). Some "weird" languages use dynamic scoping
(e.g., early versions of Perl and "pure" LISP).
- In C++, an identifier might have one of the 4 following scopes:
local scope, function scope, class scope and file scope. Your textbook
has definitions for these.
- For variables, we should also consider its allocation method
which might be automatic (for "normal" local variables), static or
- Example 1: scope of local variables. In this program we see that local variables
can be declared and defined with each block (statements between curly
braces) not just at the beginning of a function.
- Example 2: allocation of local variables. Local variables use memory
from the "stack". When a function is called, memory for the local variables
is automatically allocated on the stack. This memory is also automatically
deallocated when the function returns. This allocation method is called
"automatic", of course. (You did take notes in class when I drew those
pictures right? If not, get notes from a classmate.) The addresses of the
local variables in the second program
illustrates this concept. (sample
- Example 3: How can you have a variable declaration that isn't a
definition? Answer: external global variables.
Here we have a program that
uses a variable called info that is declared as an integer.
However, the "extern" keyword in front of the declaration says that
the storage for the variable is in fact handled in a
separate file. Thus, the
extern declaration is only a declaration and not a definition, because
storage was not allocated for info at that point.
- Example 4 & 5: The use of the keyword "static" in C and C++ is
inconsistent and confusing. Treat each use of the keyword as something
different. When we put the keyword static in front of the declaration
of a local variable, this modifies the allocation method of that
variable. Instead of putting the variable on the stack, the compiler
puts the variable in permanent (static) storage.
Our next example shows that a static
local variable can be used to count the number of times that a function is
called. Note in the sample run that
the address of a static local variable is very different from automatic
When the keyword "static" is placed in front of a global variable, this
tells the linker not to use the global variable outside the file. So,
static here, in a sense, changes the scope of that variable. It
certainly does not affect the allocation method of the global variable.
All global variables, static or otherwise, are stored in permanent
locations. Our program and
sample run of a file with a
static global variable shows that the compiler complains about not
finding a variable called info.
- The keyword static is also used in C++ class declarations.
In our header file for
the Widget class, the static data member count is used
to count the number of Widget objects that have ever been constructed.
We can do this with a static data member because there is only one copy
of count for all Widget objects. Note that in the
implementation of the Widget class
we need to define the static member count in a special way.
The use of "static" refers to the allocation method of the static data
member. In order for there to be only one copy of count, it
must essentially be a global variable (with limited access). In the
sample run of the
program that uses the Widget class,
we see that the address of count shows that it is not stored
on the stack (q.v. addresses of other data members).
To make things even more confusing, C++ also allows static
member functions. Here the use of the keyword static is very
hard to justify. The main difference between a normal member
function and a static member function is that a static member
function can be invoked without using an object of that class. In
our Widget class example, there is a static member function called
report(). This function can be invoked using the syntax
Widget::report() from the main function. Again, the use of
"static" here changes the scope of the identifier report
rather than its allocation method. Did Dante have a special circle
in Hell for people who invent especially confusing terminology?
29 Oct 1998 17:14:04 EST
to Fall 1998 CMSC 202 Section Homepage