For example, we might want to keep track of how many objects of a particular class have been created. Or we might want to have a function that is not associated with any particular object, but is still part of the class.
Whenever you see the keyword static in front of a member variable or function, think βsharedβ or βclass levelβ. A static variable is shared by all objects of a class. Only one copy of the variable exists, and if you change it in one object, it changes for all objects of that class. In this sample, we have a static variable numStudents that keeps track of how many objects of the Student class have been created. The constructor increases this value by one each time it is called. Initially, it is set to 0. After the first student is created, it changes to 1. The second student changes it to 2. And so on. When any student accesses the variable, they see the current value of that counter:
Although each constructor changes the value of numStudents, we only want to initialize it one time. So we canβt set it to 0 in the constructor. (Or each Square would reset the count to 0!). So instead, we initialize it outside the class (line 22) where we refer to it as Student::numStudents.
One important use of static variables is to declare class level constants. Say in a class Square we want to have a constant for the number of sides. We could write:
numSides is safe to make public because it is a constant - there is no danger of other code changing it in unexpected ways. And because it is public, we can access it from anywhere.
Making the constant static means that each object does not have to store a copy of the value. But it also means we donβt even need a particular Square object to name the value. Because numStudents belongs to the class, we are able to name it with Square::numSides or βthe numSides variable that is a part of the Square classβ. That trick can not be used with normal member variablesβit would not make sense to talk about Square::m_sideLength as there is no m_sideLength that is shared by all Squares; each square has its own value for that variable.
static member variables should be rare. Other than class level constants, think carefully before making a variable constant. Will it ALWAYS be the case that every object should have the same value?
Static functions are similar to static variables. They are associated with the class, not with any particular object. So we can call them without having a particular object. For example, we could write a function that returns the number of students in the class:
static int getNumStudents() {
return numStudents;
}
Because getNumStudents() is static, or βsharedβ, we should be able to ask any student for getNumStudents() and we should get the same answer. And because it does not matter who we ask, we are allowed to just ask the class itself for the answer. We can just say Student::getNumStudents() to get the value. Calling the function through the class like this instead of a particular object is only allowed when the function is static.
Since the static function does not depend on any particular object, it makes no sense to try to access normal, non-static, instance variables. Imagine if we tried to write a static function Student::getName(). What name should it return? Every student has a different name! Therefore, a static function can only access static variables and not instance variables..
static functions can only access static data or local variables. This means that any function that relies on instance variables can not be made static.
Static functions can be useful for utility functions that are related to the class but do not need to access any particular object. One example is our getNumStudents function. Another common use is to make a factory function that is used instead of a constructor to build an object. (This is only preferable when solving complex object-oriented design problems).
Imagine there is some fancy work that needs to happen every time we make a square. We might hide the normal constructor by making it private. Instead, we would provide a factory function create. Outside code must call it and let it call the constructor, giving the Square class a chance to do extra work before or after the constructor runs.
#include <iostream>
#include <string>
using namespace std;
class Square {
public:
// A static factory function to create a square object
static Square create(double size) {
// Make some decisions about how to construct the square
Square s(size); // Call the private constructor
// do some fancy other work
return s; // Return the square object
}
private:
// A private constructor that outside code cannot access
Square(double size) {
m_sideLength = size;
}
double m_sideLength; // side length of the square
};
int main()
{
// Can't use constructor directly
// Square s1(5.0); // Error: constructor is private
// Must use the static method to create a square
Square s1 = Square::create(5.0); // Use the static method to create a square
}