Você está na página 1de 10

Static data members (C++ only)

The declaration of a static data member in the member list of a class is not a d
efinition. You must define the static member outside of the class declaration, i
n namespace scope. For example:
class X
{
public:
static int i;
};
int X::i = 0; // definition outside class declaration
Once you define a static data member, it exists even though no objects of the st
atic data member's class exist. In the above example, no objects of class X exis
t even though the static data member X::i has been defined.
Static data members of a class in namespace scope have external linkage. The ini
tializer for a static data member is in the scope of the class declaring the mem
ber.
A static data member can be of any type except for void or void qualified with c
onst or volatile. You cannot declare a static data member as mutable.
You can only have one definition of a static member in a program. Unnamed classe
s, classes contained within unnamed classes, and local classes cannot have stati
c data members.
Static data members and their initializers can access other static private and p
rotected members of their class. The following example shows how you can initial
ize static members using other static members, even though these members are pri
vate:
class C {
static int i;
static int j;
static int k;
static int l;
static int m;
static int n;
static int p;
static int q;
static int r;
static int s;
static int f() { return 0; }
int a;
public:
C() { a = 0; }
};
C c;
int C::i = C::f(); // initialize with static member function
int C::j = C::i; // initialize with another static data member
int C::k = c.f(); // initialize with member function from an object
int C::l = c.j; // initialize with data member from an object
int C::s = c.a; // initialize with nonstatic data member
int C::r = 1; // initialize with a constant value
class Y : private C {} y;
int C::m = Y::f();
int C::n = Y::r;
int C::p = y.r; // error
int C::q = y.f(); // error
The initializations of C::p and C::q cause errors because y is an object of a cl
ass that is derived privately from C, and its members are not accessible to memb
ers of C.
If a static data member is of const integral or const enumeration type, you may
specify a constant initializer in the static data member's declaration. This con
stant initializer must be an integral constant expression. Note that the constan
t initializer is not a definition. You still need to define the static member in
an enclosing namespace. The following example demonstrates this:
#include <iostream>
using namespace std;
struct X {
static const int a = 76;
};
const int X::a;
int main() {
cout << X::a << endl;
}
The tokens = 76 at the end of the declaration of static data member a is a const
ant initializer.

================================================================================
=============================================
5.6. Scope of Variables
Now let's look at another distinct way to categorize variables: the scope of a v
ariable is the part of the program in which it can be accessed. Here, we are con
cerned with local scope and global scope. Variables with global scope are called
global variables. These variables are defined outside any function and therefor
e by default can be accessed from any function.1 Global variables are always in
the static storage class, as we have already seen. Variables with local scope ar
e called local variables. These variables are defined in a function and are acce
ssible only while that function is executing; they can be either static or auto
and are auto by default.
Figure 5.13 shows the valid combinations of scope and storage class.
FIGURE 5.13. Scope vs. storage class
Scope Storage class
static auto
local Y Y
global Y N

Susan had some comments on this topic.


Susan: On this scope stuff; I think you are going to have to help me understand
exactly what is inside a function and what is outside a function. I am not too s
ure I know what the difference is.
Steve: All code is inside a function. However, some variables (global variables)
are outside all functions and therefore shareable by all functions. Variables t
hat are defined inside functions are called local, because they are available on
ly to the code that's in that function.
Susan: I am validating this with you now. Please correct any misconceptions.
1. Only variables are declared outside functions.
2. No code is written outside functions.
3. Up to this point I am not to be aware of anything else going on outside a fun
ction.
Steve: Correct.
Before we get deeper into the notion of scope, I think we should revisit the que
stion of variable initialization in the light of the notion of global and local
variables. This is a difficult topic, so it wouldn't be surprising if you don't
find it obvious; Susan didn't. I wrote the next section to explain this topic to
her.
Automatic vs. Static Allocation
What makes a variable static or auto is when its storage is assigned, and theref
ore when its address is known. In the case of a static variable, this happens at
link time. In the case of an auto variable it happens when the function where i
t is defined is entered.2
This distinction affects initialization because it's impossible to initialize so
mething until you know where it is. Therefore, an auto variable cannot be initia
lized until the function where it is defined is entered. This also means that yo
u cannot assume that an auto variable will retain its value from one execution o
f the function where it's defined to the next execution of that function, becaus
e the variable might be at a different location the next time.
These restrictions do not apply to static variables, because their addresses are
known at link time and don't change thereafter. A variable defined outside all
functions (a global variable) is automatically in the static storage class, beca
use otherwise its address would never be assigned.3 Since its address is known a
t link time, the initialization of such a variable can be and is performed befor
e the start of main.
A static variable that is defined inside a function is different from one define
d globally, in that it is not initialized until the function where it is defined
is entered for the first time. However, its value is retained from one executio
n of its function to another, because its address is fixed rather than possibly
varying from one call of the function to the next as can occur with an auto vari
able. For this property to be of use, the initialization of a static variable in
a function must be performed only once; if it were performed on each entry to t
he function, the value from the previous execution would be lost. Therefore, tha
t initialization is done only once, when the function is first entered.
Susan wanted some more explanation of what happens at link time and the related
question of why we would want to use static variables.
Susan: Will you tell me again what happens at link time? Let's see, I think it g
oes like this: The source code is translated into an object file and then the ob
ject file is linked to the hardware to make executable code. Is that how it goes
?
Steve: Not quite. The object file is linked with library files containing predef
ined functions in compiled form.
Susan: Now, tell me again why you would want a variable to be static? What is th
e advantage to that? Does it just take up less room and be more efficient?
Steve: The advantage is that a static variable keeps its value from one function
call to the next. For example, suppose you wanted to count the number of times
that a function was called. You could use a static variable in the function, ini
tialize it to 0, and add 1 to it every time the function was called. When the pr
ogram was done, the value of that variable would be the number of times the func
tion was called. Obviously, we couldn't use an auto variable to do that, as it w
ould have to be initialized every time the function started or we'd have an unin
itialized variable.
Susan: I can see how using a static variable would work but I don't see why an a
uto variable couldn't do the same thing. Well, I guess it would change each time
the function would be used. Are you saying in this case that the variable has t
o be global?
Steve: Not exactly. Although we could use a global variable, we could also use a
static local variable. Figures 5.14 through 5.19 are some sample programs to il
lustrate the situation.
FIGURE 5.14. Using an auto variable and initializing it (code\count1.cpp)
#include <iostream>
using namespace std;
short counter()
{
short count = 0;
count ++;
cout << count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
FIGURE 5.15. Using an auto variable and not initializing it (code\count2.cpp)
#include <iostream>
using namespace std;
short counter()
{
short count;
count ++;
cout << count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
FIGURE 5.16. Using a local static variable and initializing it explicitly (code\
count3.cpp)
#include <iostream>
using namespace std;
short counter()
{
static short count = 0;
count ++;
cout << count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
FIGURE 5.17. Using a local static variable and not initializing it explicitly (c
ode\count4.cpp)
#include <iostream>
using namespace std;
short counter()
{
static short count;
count ++;
cout << count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
The Scope Resolution Operator
Let me interrupt the conversation here to point out something new in versions 5
and 6 of this little program: the "::" scope resolution operator. This is an exa
mple of what we were discussing in the section called "using, namespace, and std
" on page 98 in Chapter 3. Susan's question was how we would refer to our own va
riables if they had the same names as variables in the standard library. The ans
wer is to use the scope resolution operator to tell the compiler that we want to
use global identifiers defined in our source code, not ones of the same name in
the standard library. If we leave off the scope resolution operator in front of
count in these programs, the compiler will report an error when it tries to com
pile them, because there is an identifier named count in the std namespace, and
and the line using namespace std; at the beginning of each of our programs tells
the compiler that we want to be able to access all the identifiers in the std n
amespace without specifying explicitly that they are from that namespace.
Now let's continue with the analysis of scope.
FIGURE 5.18. Using a global variable and initializing it explicitly (code\count5
.cpp)
#include <iostream>
using namespace std;
short ::count = 0;
short counter()
{
::count ++;
cout << ::count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
FIGURE 5.19. Using a global variable and not initializing it explicitly (code\co
unt6.cpp)
#include <iostream>
using namespace std;
short ::count;
short counter()
{
::count ++;
cout << ::count << " ";
return 0;
}
int main()
{
short i;
for (i = 0; i < 10; i ++)
counter();
return 0;
}
Steve: Now that I've cleared that up, what will each of these programs do when r
un?
Susan: Now, let me think about this. Variables are: static or auto, global or lo
cal.
Local is for use only within functions. These variables are mostly auto, and wil
l be auto by default, but they can be static; in the latter case, they will be i
nitialized to 0.
Steve: Correct; a static numeric variable is initialized to 0 if no other provis
ion is made by the programmer to initialize it. One fine point: a local variable
can be used only within one function.
Susan: Global variables are declared only outside functions. They are always all
ocated storage at link time, like static local variables.
Steve: Correct.
Susan: Variables with static allocation are fixed because they are initialized a
t link time and thus are done just once and never change. But they can be local
or global.
Steve: Not exactly. The address of a statically allocated variable is set once a
nd never changes; its value can change just like the value of an auto variable c
an.
Susan: That's what I had mixed up. I was confusing addresses with values.
Steve: OK, as long as you're straightened out now.
Susan: An auto variable is assigned an address when the function where it is def
ined is entered. All auto variables are local.
Steve: Correct.
Susan: Now, here is where I am confused. What is the difference between at link
time and when the function where it is defined is entered? Does at link time mea
n when you are done with your source code and you are making an executable?
Steve: Yes.
Susan: And does when the function where it is defined is entered mean when the p
rogram is already made into an executable and you are running the program?
Steve: Yes.
Susan: I am confused about what we mean by initialization. I am confusing declar
ing a value for a variable and the designation of an address for a variable. It
almost seems as if we are using these two meanings for the same term. I always t
hought that initializing a variable meant just assigning a value to it.
Steve: Initializing a variable means assigning an initial value to it. In the ca
se of an auto variable, this must be done every time the function where it is de
clared is entered; whereas with a static variable, it is done once.
Susan: OK, this is what I imagined this to mean. Then how come, in your figure o
f a stack, you have values assigned to the places where the variables are?
Steve: Those values are present only after the variables to which they correspon
d have been initialized. In Figure 5.12, for example, the contents of the addres
s corresponding to Result are shown as ???, rather than as a valid value; wherea
s the values of First and Second are shown as initialized, because they have alr
eady been set to values equal to the input arguments provided by the caller.
Susan: Remember when I started tracing the "sorting" program? It had random numb
ers in the places where numbers are supposed to go, and when I actually entered
a value then those random numbers were replaced by that value. And is that why y
ou put ??? there, because you know that something is there but you don't know ex
actly what? It is just whatever until you can put a real value into those slots.
Steve: Right.
Susan: So if you leave it alone by not initializing it, then it keeps the last v
alue it had each time it goes through the loop and therefore the count goes up?
Steve: Yes, except that the initial value isn't reliable in that case. In the ca
se of the example count programs, that value happened to be 0, but there's no re
ason to expect that in general.
Susan: I want you to know that it was not immediately apparent to me just what t
he code in the example programs was doing; it really does look kinda strange. Th
en I noticed that this code called a function named counter. Why? Couldn't this
work without using a function call?
Steve: No, it wouldn't work without a function call, because the whole point is
that when a function is called, the auto variables defined in that function have
unknown values. How would I show that without a function call?
Susan: I see that. But I still don't get the point, because they all did the sam
e thing except 1. The results for that were the following: 1 1 1 1 1 1 1 1 1 1.
The results for the rest of the programs were all the same, being 1 2 3 4 5 6 7
8 9 10. So, if they all do the same thing, then what is the point? Now, what rea
lly makes me mad about this is why 1 has that result. This bothers me. Obviously
it is not incrementing itself by 1 after the first increment, it is just stayin
g at one. Oh, wait, okay, okay, maybe. . . how about this: If you initialize it
to 0 then each time it comes up through the loop it is always 0 and then it will
always add 1 to 0 and it has to do that 10 times.
Steve: Right, except that #2 does the same thing as the others only by accident;
you got lucky and happened to have a 0 as the starting value of the uninitializ
ed local variable in that example.
Susan: Then on the initialized local static variable, why does it work? Because
it is static, and because its address is one place and won't budge; that means i
ts value can increment. Well, would that mean it isn't written over in its locat
ion every time the function is called so we can add a value to it each time thro
ugh?
Steve: Right.
Susan: And then the uninitialized static one works for the same reason the auto
uninitialized one works.
Steve: Not quite. A static local variable is always initialized to something, ju
st like a global variable is. If you don't specify an initial value for a static
local numeric variable, it will be initialized to 0 during the first execution
of the function where it is defined. On the other hand, as I mentioned above, yo
u just got lucky with the uninitialized local variable example, which happened t
o have the starting value 0. Other people using other computers to run the progr
am may have different results for that example.
Susan: Now as for global, this is hard. Let me guess. Do the global initialized
and uninitialized work for the same reasons I said earlier?
Steve: The global variables are always initialized, whether you specify an initi
al value or not; if you don't specify one, it will be 0.
Susan: That's what you said about static numeric variables. Are they the same? W
ell, they have to be the same because only static variables can be global, right
?
Steve: Correct. Global variables are always statically allocated.
Susan: So if you don't initialize a numeric variable then it can become any numb
er unless it is a static numeric without explicit initialization and then it wil
l be 0 by default?
Steve: Correct.
Susan: OK, let me see if I have this. All static really means is that the variab
le is put in an address of memory that can't be overwritten by another variable
but can be overwritten when we change the variable's value?
Steve: Right.
Susan: These are tricks, and you know I don't like tricks. If they are global nu
meric variables, whether explicitly initialized or not, they are static; therefo
re they will at least have a value of 0. In example 5 this is stated explicitly
but not in example 6, so the variable also will take the value of 0 by default,
therefore these two programs are effectively identical, just like 3 and 4. That
is why examples 3, 4, 5, and 6 have the same results.
Steve: Well, obviously the trick didn't work; you crossed me up by getting the r
ight answers anyway.
Let's pause here to look at a sample program that has examples of all the types
of variables and initialization states we've just discussed. These are:4
1. global, not explicitly initialized
2. global, explicitly initialized
3. auto, uninitialized
4. auto, initialized
5. local static, not explicitly initialized
6. local static, explicitly initialized
Careful examination of the sample program shown in Figure 5.20 will help you to
visualize how and where each of these variable types might be used. As usual, yo
u can compile and run it to see what it does; running it under the debugger is p
robably more helpful than running it directly.
FIGURE 5.20. Using variables of different scopes and storage classes (code\scopc
las.cpp)
#include <iostream>
using namespace std;
short count1; // A global variable, not explicitly initialized
short count2 = 5; // A global variable, explicitly initialized
short func1()
{
short count3; // A local auto variable, not explicitly initialized
short count4 = 22; // A local auto variable, explicitly initialized
static short count5; // A local static variable, not explicitly initialized
static short count6 = 9; // A local static variable, explicitly initialized
count1 ++; // Incrementing the global variable count1.
count2 ++; // Incrementing the global variable count2.
count3 ++; // Incrementing the local uninitialized auto variable count3.
count4 ++; // Incrementing the local auto variable count4.
count5 ++; // Incrementing the local static variable count5.
count6 ++; // Incrementing the local static variable count6.
cout << "count1 = " << count1 << endl;
cout << "count2 = " << count2 << endl;
cout << "count3 = " << count3 << endl;
cout << "count4 = " << count4 << endl;
cout << "count5 = " << count5 << endl;
cout << "count6 = " << count6 << endl;
cout << endl;
return 0;
}
int main()
{
func1();
func1();
return 0;
}
FIGURE 5.21. The results of using variables of different scopes and storage clas
ses (code\scopclas.out)
count1 = 1
count2 = 6
count3 = -32715
count4 = 23
count5 = 1
count6 = 10
count1 = 2
count2 = 7
count3 = -32715
count4 = 23
count5 = 2
count6 = 11

The results shown should help to answer the question of when we would want to us
e a static variable rather than an auto variable: whenever we need a variable th
at keeps its value from one execution of a function to another. You may be wonde
ring where that weird value for count3 came from. Since we never initialized it,
we can't complain when its value is meaningless. Although the compiler can warn
us about such problems in some cases, they are still a significant source of er
rors in C++ programs, so it's worthwhile remembering to look out for them.
1
Variables can be defined either inside a function (local variables) or outside a
function (global variables); by contrast, code must always be inside a function
.
2
By the way, if you were worried about keeping track of the address of every vari
able, that's the compiler's problem, not yours. The important distinction betwee
n a static and an auto variable is when the address is assigned, not what the ac
tual address is.
3
Since all global variables are already in the static storage class, you don't ha
ve to (and shouldn't) use the keyword static when declaring a global variable. I
n another confusing legacy from C, the word static has an entirely different and
unrelated meaning when used for a global variable.
4
Remember, there aren't any global auto variables, because they would never be in
itialized.

Você também pode gostar