Menu
Coddy logo textTech

Статические методы и переменные

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 31 из 104.

Вы узнали, что статические члены являются общими для всех объектов. Теперь давайте рассмотрим, как правильно определять и использовать статические методы наряду со статическими переменными.

Статические переменные, объявленные внутри класса, должны быть определены вне класса, обычно в исходном файле. Это связано с тем, что статическим членам необходимо ровно одно место хранения, общее для всех объектов:

class Counter {
    static int count;    // Только объявление
    
public:
    Counter() { count++; }
    ~Counter() { count--; }
    
    static int getCount() {    // Статический метод
        return count;
    }
};

// Определение — требуется вне класса
int Counter::count = 0;

Статический метод принадлежит классу, а не какому-либо объекту. Это имеет важное следствие: статические методы не могут обращаться к членам экземпляра или использовать указатель this, потому что они не вызываются для какого-либо конкретного объекта.

class MathUtils {
    static double pi;
    
public:
    static double circleArea(double radius) {
        return pi * radius * radius;    // Может обращаться к статическим членам
    }
};

double MathUtils::pi = 3.14159;

// Вызывается без объекта
double area = MathUtils::circleArea(5.0);

Статические methods идеально подходят для служебных функций, которым не требуется состояние объекта, factory methods, создающих объекты, или доступа к статическим данным. Поскольку им не нужен экземпляр объекта, их вызывают с использованием имени class и оператора разрешения области видимости: ClassName::methodName().

challenge icon

Задание

Легко

Давайте создадим систему генерации уникальных ID, которая демонстрирует, как статические методы и переменные работают вместе, обеспечивая функциональность на уровне class без необходимости создавать экземпляры объектов.

Вы создадите два файла, чтобы организовать свой код:

  • IDGenerator.h: Определите class IDGenerator, который генерирует последовательные уникальные ID. В вашем class должны быть:
    • Приватный статический member nextId, отслеживающий следующий ID, который будет назначен (начинается с 1000)
    • Приватный статический member prefix (строка), хранящий настраиваемый префикс для всех ID
    • Статический method setPrefix(const std::string& p), изменяющий префикс
    • Статический method getNextId(), возвращающий строку, объединяющую префикс и текущий номер ID, а затем увеличивающий nextId для следующего вызова
    • Статический method peekNextId(), возвращающий значение следующего ID без увеличения счётчика
    • Статический method getGeneratedCount(), возвращающий количество сгенерированных ID (подсказка: вычислите его на основе начального значения и текущего nextId)
    • Статический method reset(), возвращающий nextId обратно к 1000

    Не забудьте определить статические members за пределами class после определения class. Инициализируйте prefix значением "ID-".

  • main.cpp: Продемонстрируйте вызов статических methods с использованием имени class без создания каких-либо объектов. Прочитайте пользовательский префикс из input, затем:
    • Выведите "Peek: <peeked_id>" с помощью peekNextId()
    • Сгенерируйте три ID с помощью getNextId() и выведите каждый в виде "Generated: <id>"
    • Выведите "Count: <count>", показывая, сколько ID было сгенерировано
    • Измените префикс, используя значение из input и setPrefix()
    • Сгенерируйте ещё два ID и выведите каждый в виде "Generated: <id>"
    • Снова выведите "Count: <count>"
    • Вызовите reset()
    • Выведите "After reset - Peek: <peeked_id>"
    • Выведите "After reset - Count: <count>"

Обратите внимание, что вы никогда не создаёте объект IDGenerator: все methods вызываются непосредственно у class с использованием IDGenerator::methodName(). Это ключевая характеристика статических methods: они принадлежат самому class, а не какому-либо конкретному экземпляру.

Подключите <string> и <iostream> в своём заголовочном файле и не забудьте про защиту заголовочного файла.

Попробуйте сами

#include <iostream>
#include <string>
#include "IDGenerator.h"

using namespace std;

int main() {
    // Прочитать пользовательский префикс из ввода
    string customPrefix;
    cin >> customPrefix;
    
    // TODO: Вывести "Peek: <peeked_id>" с помощью peekNextId()
    
    // TODO: Сгенерировать три ID с помощью getNextId() и вывести каждый как "Generated: <id>"
    
    // TODO: Вывести "Count: <count>", показывая, сколько ID было сгенерировано
    
    // TODO: Изменить префикс, используя значение из ввода, с помощью setPrefix()
    
    // TODO: Сгенерировать ещё два ID и вывести каждый как "Generated: <id>"
    
    // TODO: Вывести "Count: <count>" снова
    
    // TODO: Вызвать reset()
    
    // TODO: Print "After reset - Peek: <peeked_id>"
    
    // TODO: Print "After reset - Count: <count>"
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++