Члены экземпляра против статических
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 27 из 104.
До сих пор каждая созданная тобой переменная-член принадлежит определённому объекту. Когда ты создаёшь два объекта Player, у каждого есть собственные name и health. Они называются членами экземпляра — они существуют отдельно для каждого экземпляра класса.
Но что, если вам нужны данные, общие для всех объектов? Например, отслеживать, сколько всего существует игроков.
Именно здесь на помощь приходят статические члены. Статический член принадлежит самому классу, а не какому-либо конкретному объекту.
class Player {
std::string name; // Член экземпляра — у каждого игрока свой
int health; // Член экземпляра
static int playerCount; // Статический член — общий для ВСЕХ игроков
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Увеличиваем при создании любого игрока
}
~Player() {
playerCount--; // Уменьшаем при уничтожении любого игрока
}
};Ключевое различие: доступ к членам экземпляра осуществляется через объект, тогда как к статическим членам можно обращаться непосредственно по имени class. Считай, что члены экземпляра — это «по одному на объект», а статические члены — «по одному на class».
| Члены экземпляра | Статические члены |
|---|---|
| Уникальны для каждого объекта | Общие для всех объектов |
| Создаются при создании объекта | Существуют до создания любого объекта |
Доступны через объект: player.health | Доступны через класс: Player::playerCount |
Статические члены полезны для счётчиков, значений конфигурации или любых данных, которые логически относятся к классу, а не к отдельным объектам.
Задание
ЛегкоДавайте создадим систему учёта товаров, которая отслеживает сведения как об отдельных товарах, так и об общей статистике инвентаря с использованием экземплярных и статических членов.
Вы создадите два файла, чтобы организовать код:
Product.h: Define классProduct, который управляет отдельными товарами и одновременно отслеживает данные по всему инвентарю. Ваш класс должен иметь:- Экземплярные члены:
name(строка) иprice(double): уникальные для каждого товара - Статический член
totalProducts, который подсчитывает, сколько товаров существует current - Статический член
totalValue, который отслеживает совокупную цену всех товаров - constructor, принимающий name и price, инициализирующий экземплярные члены и обновляющий оба статических счётчика (увеличить count, добавить price к общей стоимости)
- destructor, который обновляет статические счётчики при удалении товара (уменьшить count, вычесть price из общей стоимости)
- Метод
getInfo(), возвращающий строку в формате:"<name>: $<price>" - Статический метод
getInventoryStats(), возвращающий строку:"Products: <count>, Total Value: $<value>"
- Экземплярные члены:
main.cpp: Продемонстрируйте, как статические члены являются общими для всех объектов, тогда как экземплярные члены остаются уникальными. Считайте из входных данных два названия товаров и их цены (name1, price1, name2, price2: каждое на отдельной строке), затем:- Выведите начальную статистику инвентаря, используя имя класса:
Product::getInventoryStats() - Создайте блок области видимости с фигурными скобками и внутри него создайте
Productс первым названием и ценой. Выведите сведения о нём и current статистику инвентаря. - After завершения блока (первый товар уничтожен) выведите
"After first scope:", а затем статистику инвентаря - Создайте another
Productсо вторым названием и ценой. Выведите сведения о нём и статистику инвентаря. - Создайте третий
Productс названием"Bonus"и ценой5.00. Выведите итоговую статистику инвентаря.
- Выведите начальную статистику инвентаря, используя имя класса:
Не забудьте определить статические члены вне класса в файле заголовка (после определения класса). Форматируйте цены с двумя десятичными знаками, используя std::fixed и std::setprecision(2) из <iomanip>.
Include файл заголовка в main.cpp с помощью #include "Product.h".
Попробуйте сами
#include <iostream>
#include <string>
#include "Product.h"
using namespace std;
int main() {
// Прочитать ввод
string name1;
double price1;
string name2;
double price2;
getline(cin, name1);
cin >> price1;
cin.ignore();
getline(cin, name2);
cin >> price2;
// TODO: Вывести начальную статистику инвентаря с помощью Product::getInventoryStats()
// TODO: Создать блок области видимости с фигурными скобками
// Внутри блока:
// - Создать Product с name1 и price1
// - Вывести его информацию с помощью getInfo()
// - Вывести текущую статистику инвентаря
// TODO: After the block ends, print "After first scope:"
// Затем вывести статистику инвентаря
// TODO: Создать ещё один Product с name2 и price2
// Вывести его информацию и статистику инвентаря
// TODO: Создать третий Product с именем "Bonus" и ценой 5.00
// Вывести итоговую статистику инвентаря
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++