Search

8.12 — Static member functions

Static member functions

In the previous lesson on static member variables, you learned that static member variables are member variables that belong to the class rather than objects of the class. If the static member variables are public, we can access them directly using the class name and the scope resolution operator. But what if the static member variables are private? Consider the following example:

In this case, we can’t access Something::s_value directly from main(), because it is private. Normally we access private members through public member functions. While we could create a normal public member function to access s_value, we’d then need to instantiate an object of the class type to use the function! We can do better. It turns out that we can also make functions static.

Like static member variables, static member functions are not attached to any particular object. Here is the above example with a static member function accessor:

Because static member functions are not attached to a particular object, they can be called directly by using the class name and the scope resolution operator. Like static member variables, they can also be called through objects of the class type, though this is not recommended.

Static member functions have no *this pointer

Static member functions have two interesting quirks worth noting. First, because static member functions are not attached to an object, they have no this pointer! This makes sense when you think about it -- the this pointer always points to the object that the member function is working on. Static member functions do not work on an object, so the this pointer is not needed.

Second, static member functions can directly access other static members (variables or functions), but not non-static members. This is because non-static members must belong to a class object, and static member functions have no class object to work with!

Another example

Static member functions can also be defined outside of the class declaration. This works the same way as for normal member functions.

Here’s an example:

This program prints:

The next ID is: 1
The next ID is: 2
The next ID is: 3
The next ID is: 4
The next ID is: 5

Note that because all the data and functions in this class are static, we don’t need to instantiate an object of the class to make use of its functionality! This class utilizes a static member variable to hold the value of the next ID to be assigned, and provides a static member function to return that ID and increment it.

A word of warning about classes with all static members

Be careful when writing classes with all static members. Although such “pure static classes” (also called “monostates”) can be useful, they also come with some potential downsides.

First, because all static members are instantiated only once, there is no way to have multiple copies of a pure static class (without cloning the class and renaming it). For example, if you needed two independent IDGenerator objects, this would not be possible with a single pure static class.

Second, in the lesson on global variables, you learned that global variables are dangerous because any piece of code can change the value of the global variable and end up breaking another piece of seemingly unrelated code. The same holds true for pure static classes. Because all of the members belong to the class (instead of object of the class), and class declarations usually have global scope, a pure static class is essentially the equivalent of declaring functions and global variables in a globally accessible namespace, with all the requisite downsides that global variables have.

C++ does not support static constructors

If you can initialize normal member variables via a constructor, then by extension it makes sense that you should be able to initialize static member variables via a static constructor. And while some modern languages do support static constructors for precisely this purpose, C++ is unfortunately not one of them.

If your static variable can be directly initialized, no constructor is needed: you can initialize the static member variable at the point of definition (even if it is private). We do this in the IDGenerator example above. Here’s another example:

If initializing your static member variable requires executing code (e.g. a loop), there are many different, somewhat obtuse ways of doing this. The following code presents one of the better methods. However, it is a little tricky, and you’ll probably never need it, so feel free to skip the remainder of this section if you desire.

When static member s_initializer is defined, the _init() default constructor will be called (because s_initializer is of type _init). We can use this constructor to initialize any static member variables. The nice thing about this solution is that all of the initialization code is kept hidden inside the original class with the static member.

Summary

Static member functions can be used to work with static member variables in the class. An object of the class is not required to call them.

Classes can be created with all static member variables and static functions. However, such classes are essentially the equivalent of declaring functions and global variables in a globally accessible namespace, and should generally be avoided unless you have a particularly good reason to use them.

8.13 -- Friend functions and classes
Index
8.11 -- Static member variables

104 comments to 8.12 — Static member functions

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    So, the whole point of static class members is using class functionalities without making any instances. Is this correct? Or are there other purposes?

    If it is, what is the point? Do static class members have uses in C++?

    • > Is this correct?
      Yes.

      > what is the point?
      A function is considered to be a part of a class, but it doesn't need an instance to work. If you want to use the function and don't have an instance, what do you do? Instantiation the class wastes resources. Even if you instantiated it, what do you initialize it to?

      > Do static class members have uses in C++?
      Yes, you'll see reasons to use `static` member functions later.

  • McDidda

    Hi,
    Consider the following snippet

    I'm not getting how line 8 and line 11 works (I was expecting compiler to throw error,as x is just member variable and it'll be attached with "enclose" object but still line 11 gets compiled in given snippet).

  • sekhar

    Hi Alex,

    Why does static variable defined inside a static function(here *inst of getInstance() function & val2 of printSample() static function) does not require it to be defined outside the class similar to any static variable declared as part of private/public section of a class(m_id  defined outside the class) ?

    • Alex

      In the above example, the "static int m_id" inside class Sample serves as a declaration, not a definition (as no memory is allocated until the class is instantiated). Because static member objects can be accessed even without an object, the definition needs to be somewhere. Thus, it's defined outside the class.

      In the case of inst, inst is a local static variable and is scoped to the function. Inst's declaration is also it's definition, so no separate definition is needed.

  • Ishak

    "First, because all static members are instantiated only once, there is no way to have multiple copies of a pure static class (without cloning the class and renaming it). For example, if you needed two independent IDGenerator objects, this would not be possible with a single pure static class."

    Isn't this the case with normal classes too? I can't have two IDGenerator objects, since all the objects share the same static members.

    "class declarations usually have global scope, a pure static class is essentially the equivalent of declaring functions and global variables in a globally accessible namespace, with all the requisite downsides that global variables have."

    Yeah but is it really as bad as global variables, even though I have static member functions that dictate how we can interact with the static variables ?

    thanks for the help

    • > Isn't this the case with normal classes too? I can't have two IDGenerator objects, since all the objects share the same static members.
      This is the case for every class with static members.

      > Yeah but is it really as bad as global variables
      No, they're nested in a class and access can be controlled via functions. I think Alex exaggerated in this sentence.

  • tinu

    Are MyClass::s_mychars and MyClass::s_initializer being defined twice in the last code example?

  • Gizmo

    I'm trying to implement a static function member using class headers and .cpp files, and I'm having trouble getting it to work.

    Here is a piece of example code demonstrating the issue.

    Example.h:

    Example.cpp:

    When I try to build the program, I get this error:
    "error: cannot declare member function 'static void Example::example()' to have static linkage [-fpermissive]"

    What am I doing wrong?

  • Nimbok

    In the section on static constructors (the lack thereof), is there a reason to use an inner class instead of a static function to initialize the vector? An initializer function could be called multiple times, inappropriately, but you can do the same with the inner class approach by instantiating another one (MyClass::_init ohno;). This would push another 'a', 'e', 'i', 'o', and 'u' onto the vector.

    • nascardriver

      Hi Nimbok!

      > is there a reason to use an inner class instead of a static function to initialize the vector?
      Using a class has the advantage that the constructor is automatically called when the object is created whereas we'd need to manually call a function.

      > An initializer function could be called multiple times
      The @_init class should be declared private, not public. If that was the case you wouldn't be able to create another @_init object outside of @MyClass.
      Alternatively (but less efficient) one could check @s_mychars.empty() to see if the vector has already been filled.

  • Guozili

    Hi Alex,
    When you talk about warnings about classes with all static members, you mentioned that "First, because all static members are instantiated only once, there is no way to have multiple copies of a pure static class (without cloning the class and renaming it). For example, if you needed two independent IDGenerator objects, this would not be possible with a single pure static class."
    But I still could not understand it, if I define:

    Something wrong?

    • nascardriver

      Hi Guozili!

      The problem here is that A and B are equivalent. Take the following code for example

      Expected output

      Actual output

      You cannot have two different IDGenerators with all static members.

  • Mr. Nobody

    Thanks alot...
    XXX

  • Luhan

    At the end of tutorial you show how to initialize a static vector through iteration, i didn't understand this:

    is this  _init  a class, and you create this member so when you define it at the same time the constructor is called and executes the push inside the vector?

  • Cunni

    Hi Alex,
    In the paragraph of the A word of warning about classes with all static members section, you wrote:

    "(...)Because all of the members belong to the class (instead of object of the class), and class declarations usually have global scope, a pure static class is essentially the equivalent of declaring functions and global variables in a globally accessible namespace, with all the requisite downsides that global variables have."

    This only applies to static members that are within the public accessors, correct? If the static members are made private, than they are no longer in the global namespace?

    • Alex

      Well, the class members aren't in the global namespace either way (they're in the class namespace, which is in the global namespace) -- but the end result is similar, the members are accessible by everybody from everywhere.

      If you make those members private, then they can no longer be accessed from outside the class, which helps alleviate the issue.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]