Generally, each object instantiated from a class maintains its own distinct copy of each member variable declared in the class. So, in a sense, the object "owns" the member variables, and programs must access them through their owners. However, sometimes programs need to manage data that is accessible by various combinations of many objects (the Pouring Puzzle example presented later in the chapter illustrates this situation). We could implement the data as global variables, but we've seen that globals are error-prone, so we seek a more secure, object-oriented solution. The object-oriented programming languages implement the solution as class variables. Whereas member variables belong to specific objects, class variables belong to all instances of a given class. Like Java, C++ implements class variables with the static keyword (please see footnote 1).
Non-static or class members (attributes and operations) belong to individual instances of the class (i.e., objects). On the other hand, static or class features "belong" to the class. The contrast between the two ownerships constitutes a significant difference between static and non-static features. The UML provides additional notation to differentiate between the kinds of ownership. Unless otherwise specified, features in a UML class diagram are non-static and have instance (i.e., object) ownership. Alternatively, the UML denotes static features with class ownership by underlining the feature in the class diagram. Programmers translate the underlining to the static keyword when they translate the UML class diagram to C++.
static features by underlining them. The static keyword may modify attributes and operations alike and is independent of other modifiers such as public or private.
To help us understand the role static features play in C++ programs, imagine that we want to write a program that counts the total number of objects it instantiates from class. Our approach is simple: define a variable named count to count each object as the program creates it. Consider the following problems that arise if we define count as a non-static or member variable:
We could define count outside the class, but this violates strong encapsulation. Good object-oriented design "hides" everything about a class in the class itself and provides controlled access through a public interface. Programmers use static variables whenever they need to use data related to a class but not bound to a specific object. This practice maintains strong encapsulation while addressing the problems listed above.
Although programs can access static variables through objects, these variables "belong" to a class. Consequently, they exist even when the program hasn't instantiated any objects from the class and after it has destroyed any objects. This observation implies that we need a class-level notation to manage static variables independently of any object. Furthermore, that notation must be sufficiently robust to support any functions that access the variables, including getter and setter functions. C++ bases the notation on the scope resolution operator, ::. When programmers use the scope resolution operator to define or use a variable or function, the code looks very much like it did when they used the operator with namespaces.
| Foo.h | Foo.cpp |
|---|---|
class Foo
{
private:
int var1;
int var2;
static int count;
public:
Foo();
static int get_count();
};
|
#include "Foo.h"
int Foo::count = 0; // define and initialize
Foo::Foo()
{
count++;
}
int Foo::get_count()
{
return count;
} |
| (a) | (b) |
| Client | Memory Layout |
#include <iostream>
#include "Foo.h"
using namespace std;
int main()
{
Foo f0;
Foo f1;
Foo f2;
cout << f0.get_count() << endl; // works not preferred
cout << Foo::get_count() << endl; // preferred
return 0;
} |
![]() |
| (c) | (d) |
static keyword. Programmers use class variables to save data that applies to all class instances rather than specific objects. The "skeletonized" code shown here is simplified to illustrate the concept and syntax of class variables and functions. Please see the Pouring Puzzle problem later in this chapter for an authentic example.
static keyword only appears in the class specification.static variables in the class specification.static functions through an object, calling them with the class name is preferred. C++ only allows static functions to be called through the class name, so this notation signals a reader that the function is static and allows programmers to call the function when an object isn't available.
static functions do not have a "this" pointer, and so cannot access any non-static class variables or functions.static variables outside of all objects, which means that the variables exist in the absence of any objects. Programs can access the variable by name, but they can't access it via a "this" pointer because it is not part of an object.A symbolic constant is an unchangeable value named for clarity or convenience. C++ inherits two ways of creating symbolic constants from the C programming language: create macros with #define or use enumerations. The first technique makes it difficult to restrict the constant to class scope, and the second technique is limited to integer constants. But we can also create constants with const keyword, and these can be any data type, follow all scoping rules, and can represent any valid data type. We can easily make these into class constants whose scope is limited to member functions by placing them inside a class.
class foo
{
public:
const static double MAGIC = 2.7;
void function();
}; |
class bar
{
public:
const static double MAGIC = 3.14;
void function();
}; |
| (a) | |
void foo::function()
{
... MAGIC ...
} |
void bar::function()
{
... MAGIC ...
} |
| (b) | |
void application1()
{
... foo::MAGIC ...
} |
void application2()
{
... bar::MAGIC ...
} |
| (c) | |
static and const, used in conjunction, form class constants. The code fragments illustrate the syntax for defining, initializing, and using class constants.
static makes them belong to the class as a whole - programs may use the constants independent of any object. Making them const prevents the application (or any other code) from changing the value.