|
| Tuesday, November 24 |
| Statics |
C++ style constants (often called constant variables, if that can make sense).
- A constant is just a variable that is set once and never changed. From
the computer's viewpoint, it handles variables and constants exactly the same
way.
- The compiler can check if a variable is changed, and therefore enforce if that
"variable" is really a constant at compile time. If you declare a
"variable" to be constant, then the compiler makes sure that it is not changed
after the initialization.
- constants in C++ are just variables declared
const.
They must be initialized in the declaration. The compiler will enforce the
initialization, and will give a compiler error if your code subsequently tries
to change the value in the constant "variable".
- constant variables are much safer than
#defines
and should usually be used instead of
#defines
const double PI = 3.14159;
static variables and constants in classes
- As you know, if you declare an instance variable inside a class definition,
there will be a separate variable for each object you create for that class.
Each class has its own set of instance variables that it controls.
- Unfortunately, this is also true if you declare a constant inside the class.
Even though the constant will be the same value for each object, each object
will still have its own copy. This is very space inefficient if you create
a lot of objects for that class.
- Declaring a constant, or a variable, to be
static
means there will be one and only one instance of that constant or variable, no
matter how many objects are created.
- Each object will still think that it has a private copy of that constant or
variable, but in reality all objects of that class will share the same single
constant or variable.
- For example, for the silly
class Blipple
class Blipple
{
private:
const string SPECIES = "Blipple";
string name;
public:
Blipple(string n) name(n) {};
string whatsyourspecies() {return SPECIES;};
string whatsyourname() {return name;};
};
- Defined this way, every Blipple object will have its own
SPECIES
string, "Blipple".
If there are 1000 Blipples, then there will be 1000 copies of the string.
That is very wasteful.
string name;
however, will be different for each Blipple (hopefully), and 1000 different name
strings, one per object, makes sense.
- Also, since SPECIES can never be changed, there is no reason to keep it
private.
Whether to make a constant private or public is a design decision, but either
way is good programming. If only objects of that class are going to use
the constant, then keep it
private.
If there is any reason that other parts of your code will need the constant's
value, make it
public.
- The problems can be solved with the following small changes:
class Blipple
{
private:
string name;
public:
const static string SPECIES = "Blipple";
Blipple(string n) name(n) {};
string whatsyourspecies() {return SPECIES;};
string whatsyourname() {return name;);
};
- By adding static
to the SPECIES
declaration, it means that one and only one string will be stored in memory.
Each object can refer to it, and each object thinks that it is its "own"
constant, but all Blipples will really be sharing the same string. Since
it cannot be changed, there is no problem with multiple objects sharing it.
- However there is a problem with the initialization. Theoretically, it
will be initialized each time an object is created. This is a problem
because a constant can only be initialized once. The above code will not
compile.
- Instead, you don't initialize a static variable inside the class.
You initialize it once before the program starts. This is done by putting
what is essentially a duplicate global definition before the
int main().
You could also put it in a header file, .h, but it must be read before the
compiler gets to
int main().
- Here is the corrected syntax:
class Blipple
{
private:
string name;
public:
const static string SPECIES;
Blipple(string n) name(n) {};
string whatsyourspecies() {return SPECIES;};
string whatsyourname() {return name;);
};
// in .h or .cpp before int main()
const string Blipple::SPECIES = "Blipple";
int main()
{
// and so on...
-
This syntax has been criticized because there are two declarations, even though
only one variable is actually created. Notice also that the global
definitions of
const
string Blipple::SPECIES;
does not contain the keyword
static
but the declaration inside the class,
const static string SPECIES;
does. C++ syntax only allows
static
used inside a class
declaration. It cannot be used outside the class definition, even for the
initializations
for that class's static variables.
- If you use
static
for a variable, all the concepts are the same, except you are now allowed to
change the static variable. This means that any object of that class will
use the static variable as if it were its own private instance variable, but if
one object changes it, all the other objects will see the change in their "own"
variable. This allows sharing of information among all objects of a class.
- As an example:
class Blipple
{
private:
string name;
static int numberofblipples;
public:
const static string SPECIES;
Blipple(string n) name(n) {numberofblipples++;};
~Blipple() {numberofblipples--;};
string whatsyourspecies() {return SPECIES;};
string whatsyourname() {return name;);
int howmanyblipples() {return numberofblipples;);
};
// in .h or .cpp before int main()
const string Blipple::SPECIES = "Blipple";
int Blipple::numberofblipples = 0;
int main()
{
// and so on...
-
Notice that when each Blipple is constructed
numberofblipples; incremented.
Since all these Blipple constructors are incrementing the same single variable,
numberofblipples
will keep track of how
many Blipples have been created in total. Also the Blipple destructor will
ensure that numberofblipples
always contains how many active Blipples are executing at any time.
- Each Blipple can refer to it "own" copy of
numberofblipples
to know how many Blipples are active. The value is effectively distributed
to all Blipples because the variable is static.
- In addition, if no Blipples have been created yet,
numberofblipples
will still exist, with its initial value of 0, because
numberofblipples
is the same as a global variable, except it belongs to
class Blipple.
- If a constant is public and static, then it can be used in any code by putting
the class name before the dot, not necessarily an object name of that
class. The static constant is accessible independently of any object.
- If you want, you can still access the static constant using an object's name.
It does not matter which object's name you use, because you will get the same
value from any object of that class at any given time in your program's
execution.
Blipple jian("Jian"), lisa("Lisa"),
henry{"Henry");
// later in your code
cout << "Lisa is a " << lisa.SPECIES << endl;
static functions
- In addition, member functions inside a class can be declared
static
if the function does not
access or change any non-static instance variables. In other words,
static
functions can only use
static
instance variables, or no
instance variables at all.
class Blipple
{
private:
string name;
static int numberofblipples;
public:
const static string SPECIES;
Blipple(string n) name(n) {numberofblipples++;};
~Blipple() {numberofblipples--;};
static string whatsyourspecies() {return SPECIES;};
string whatsyourname() {return name;);
static int howmanyblipples() {return numberofblipples;);
};
- In the above Blipple definition,
howmanyblipples()
and whatsyourspecies
meet that definition, but
whatsyourname()
does not.
Therefore, anywhere in your code you can get the SPECIES or numberofblipples by
using the static function calls:
// no change
cout << "There are now " << Blipple.howmanyblipples() << " Blipples." << endl;
cout << "Jain is a " << Blipple.whatsyourspecies() << "." << endl;
- The second
function is reduntent, however, because
SPECIES
is public. You
could also write:
cout << "Jain is a " << Blipple.SPECIES << "." << endl;
or
cout << "Jain is a " << jian.SPECIES << "." << endl;
-
Whenever a function accesses only static instance variables or no instance
variables at all, it should be declared
static.
This allows the users to call the function using the ClassName. syntax,
even if there is no object of that class in scope at that point in the code.
static functions calling other functions
- A
static function can only call another static function. This should make
sense, because if a static function could call a non-static function, then that
non-static might change a non-static instance variable, which is forbidden for a
static function.
- The mnemonic is "If static, only static".
- Non-static functions can call any function within the class, static or
non-static, and access any constant or variable, static or non-static. A
non-static function is allowed to change any instance variables, so it does not
matter whether the functions it calls changes static variables or non-static
variables.
- The mnemonic is "If not static, anything".
Readings
Deitel and Deitel Fifth Edition, Chapter ?.?, ?.?, ?.?
| Back to Csc 125 Programming in C++ |
| Scott Badman Office: B132 Phone: 353-2250 sbadman@parkland.edu |
Parkland College, 2400 W. Bradley Avenue, Champaign, IL 61821 |