#123 – Static methods: functions that belong to the class

Just like static members variables, static methods are also a thing. They can be called directly using ::.

Calling a static method through the class

Since static methods belong to the class they can be called directly.

#include <iostream>
#include <utility>

class BatteryMonitorConfig {
private:
    static inline int s_samplePeriodMs { 1000 };
    static inline std::pair s_safeVoltageRange { 3.0, 4.2 };

public:
    static int samplePeriodMs(){
        return s_samplePeriodMs;
    }

    static bool isVoltageSafe(double voltage){
        return voltage >= s_safeVoltageRange.first
            && voltage <= s_safeVoltageRange.second;
    }
};

int main(){
    std::cout << "Sample period: "
              << BatteryMonitorConfig::samplePeriodMs() << " ms\n";

    std::cout << std::boolalpha;
    std::cout << "3.7 V safe: "
              << BatteryMonitorConfig::isVoltageSafe(3.7) << '\n';

    std::cout << "4.6 V safe: "
              << BatteryMonitorConfig::isVoltageSafe(4.6) << '\n';
}

Terminal output:
Sample period: 1000 ms
3.7 V safe: true
4.6 V safe: false

No BatteryMonitorConfig object is created.

The static methods are called directly through the class:

BatteryMonitorConfig::samplePeriodMs()
BatteryMonitorConfig::isVoltageSafe(3.7)

Accessors are easy candidates for static

Accessor methods should be assigned static since they belong to the class and not the class objects.

See the program below. A static method is used as a getter for a static member.

#include <iostream>

class Something
{
private:
    static inline int s_value { 1 };

public:
		// Static method
    static int getValue() { return s_value; }
};

int main()
{
		// We can call the static method without instantiating the class
    std::cout << Something::getValue() << '\n';
}

Static member functions have no this pointer

Since static methods belong to the class, they have no this pointer. This makes sense as no object can hold a static method.

If a static method wishes to operate on private member variables, it must accept an object (i.e. use the public interface):

#include <iostream>

class Counter {
private:
    int m_value {};

public:
    explicit Counter(int value)
        : m_value { value }
    {
    }

		// Accepts a reference to a Counter object
    static void reset(Counter& counter)
    {
        counter.m_value = 0;
    }

    void print() const
    {
        std::cout << m_value << '\n';
    }
};

int main()
{
    Counter counter { 42 };

    Counter::reset(counter);

    counter.print();
}

Terminal output:
0

The singleton pattern uses a static method

This makes sense since we only want one instance of an object which belongs to the class itself.

For example, in my text PRG, EventBus::Instance() is static:

// .h
static EventBus& Instance();

// .cpp
EventBus& EventBus::Instance() {
    static EventBus instance;
    return instance;
}

The motivation is to have a single Eventbus that is shared across the code base.

In Summary

  • A static member function belongs to the class, not to one object.
  • A static member function can be called with ClassName::function().
  • A static member function has no this pointer.