C++ Programming

From Wikibooks, open books for an open world
Jump to navigation Jump to search

The static keyword can be used in four different ways:


Clipboard

To do:
Alter the above links from subsection to book locations after the structure is fixed.


The static keyword can also be used on functions, inside functions, on classes, on classes members (data and functions), in structs, unions (but not in a union's member) we will cover each use separately.

Permanent storage[edit | edit source]

Using the static modifier makes a variable have static lifetime and on global variables makes them require internal linkage (variables will not be accessible from code of the same project that resides in other files).

static lifetime
Means that a static variable will need to be initialized in the file scope and at run time, will exist and maintain changes across until the program's process is closed, the particular order of destruction of static variables is undefined.

static variables instances share the same memory location. This means that they keep their value between function calls. For example, in the following code, a static variable inside a function is used to keep track of how many times that function has been called:

void foo() {
  static int counter = 0;
  cout << "foo has been called " << ++counter << " times\n";
}

int main() {
  for( int i = 0; i < 10; ++i ) foo();
}
Internal linkage

When used on a free function, a global variable, or a global constant, it specifies internal linkage (as opposed to extern, which specifies external linkage). Internal linkage limits access to the data or function to the current file.

Examples of use outside of any function or class:

static int apples = 15;
defines a "static global" variable named apples, with initial value 15, only visible from this translation unit.
static int bananas;
defines a "static global" variable named bananas, with initial value 0, only visible from this translation unit.
int g_fruit;
defines a global variable named g_fruit, with initial value 0, visible from every translation unit. Such variables are often frowned on as poor style.
static const int muffins_per_pan=12;
defines is a variable named muffins_per_pan, visible only in this translation unit. The static keyword is redundant here.
const int hours_per_day=24;
defines a variable named hours_per_day, only visible in this translation unit. (This acts the same as
static const int hours_per_day=24;
).
static void f();
declares that there is a function f taking no arguments and with no return value defined in this translation unit. Such a forward declaration is often used when defining mutually recursive functions.
static void f(){;}
defines the function f() declared above. This function can only be called from other functions and members in this translation unit; it is invisible to other translation units.
static member function[edit | edit source]

Member functions or variables declared static are shared between all instances of an object type. Meaning that only one copy of the member function or variable does exists for any object type.

member functions callable without an object

When used in a class function member, the function does not take an instantiation as an implicit this parameter, instead behaving like a free function. This means that static class functions can be called without creating instances of the class:

class Foo {
public:
  Foo() {
    ++numFoos;
    cout << "We have now created " << numFoos << " instances of the Foo class\n";
  }
  static int getNumFoos() {
    return numFoos;
  }
private:
  static int numFoos;
};

int Foo::numFoos = 0;  // allocate memory for numFoos, and initialize it

int main() {
  Foo f1;
  Foo f2;
  Foo f3;
  cout << "So far, we've made " << Foo::getNumFoos() << " instances of the Foo class\n";
}
Named constructors[edit | edit source]

Named constructors are a good example of using static member functions. Named constructors is the name given to functions used to create an object of a class without (directly) using its constructors. This might be used for the following:

  1. To circumvent the restriction that constructors can be overloaded only if their signatures differ.
  2. Making the class non-inheritable by making the constructors private.
  3. Preventing stack allocation by making constructors private

Declare a static member function that uses a private constructor to create the object and return it. (It could also return a pointer or a reference but this complication seems useless, and turns this into the factory pattern rather than a conventional named constructor.)

Here's an example for a class that stores a temperature that can be specified in any of the different temperature scales.

class Temperature
{
    public:
        static Temperature Fahrenheit (double f);
        static Temperature Celsius (double c);
        static Temperature Kelvin (double k);
    private:
        Temperature (double temp);
        double _temp;
};

Temperature::Temperature (double temp):_temp (temp) {}

Temperature Temperature::Fahrenheit (double f)
{
    return Temperature ((f + 459.67) / 1.8);
}

Temperature Temperature::Celsius (double c)
{
    return Temperature (c + 273.15);
}

Temperature Temperature::Kelvin (double k)
{
    return Temperature (k);
}

static data member[edit | edit source]

The use of the static specifier in a data member, will cause that member to be shared by all instances of the owner class and derived classes. To use static data members you must declare the data member as static and initialize it outside of the class declaration, at file scope.

When used in a class data member, all instantiations of that class share one copy of the variable.

class Foo {
public:
  Foo() {
    ++iNumFoos;
    cout << "We have now created " << iNumFoos << " instances of the Foo class\n";
  }
private:
  static int iNumFoos;
};

int Foo::iNumFoos = 0;  // allocate memory for numFoos, and initialize it

int main() {
  Foo f1;
  Foo f2;
  Foo f3;
}

In the example above, the static class variable numFoos is shared between all three instances of the Foo class (f1, f2 and f3) and keeps a count of the number of times that the Foo class has been instantiated.