Классы хранения в C++
Здравствуйте, начинающие программисты! Сегодня мы отправимся в увлекательное путешествие по миру классов хранения в C++. Не волнуйтесь, если вы новички в программировании; я буду вашим доброжелательным проводником, объясняя все шаг за шагом. Погружаемся!
Что такое классы хранения?
Прежде чем мы перейдем к деталям, давайте поймем, что такое классы хранения. В C++ классы хранения определяют область действия (видимость) и срок жизни переменных и функций в программе. Они告诉 компилятору, как хранить переменную, доступна ли она из других файлов и как долго она должна существовать в памяти.
Теперь давайте рассмотрим каждый класс хранения подробно.
Класс хранения auto
Ключевое слово auto
в C++ изменило свое значение с течением времени. В современном C++ (C++11 и новее) оно используется для типизации. Однако в старых версиях это был спецификатор класса хранения.
Старое использование (до C++11):
int main() {
auto int x = 5; // Эквивалентно: int x = 5;
return 0;
}
В этом старом использовании auto
явно декларировал переменную с автоматическим сроком хранения. Однако это было по умолчанию для локальных переменных, поэтому использовалось редко.
Современное использование (C++11 и новее):
int main() {
auto x = 5; // x выводится как int
auto y = 3.14; // y выводится как double
auto z = "Hello"; // z выводится как const char*
return 0;
}
В современном C++, auto
позволяет компилятору выводить тип переменной на основе ее инициализатора. Это особенно полезно с сложными типами или когда тип может измениться в будущем.
Класс хранения register
Ключевое слово register
является подсказкой компилятору, что эта переменная будет часто использоваться и должна быть сохранена в регистре ЦП для faster доступа.
#include <iostream>
int main() {
register int counter = 0;
for(int i = 0; i < 1000000; i++) {
counter++;
}
std::cout << "Счетчик: " << counter << std::endl;
return 0;
}
В этом примере мы предлагаем компилятору сохранить counter
в регистре. Однако современные компиляторы обычно умны достаточно, чтобы делать такие оптимизации самостоятельно, поэтому register
редко используется на практике.
Класс хранения static
Ключевое слово static
имеет разные значения в зависимости от того, где оно используется:
1. Статические локальные переменные
#include <iostream>
void countCalls() {
static int calls = 0;
calls++;
std::cout << "Эта функция была вызвана " << calls << " раз(а)." << std::endl;
}
int main() {
for(int i = 0; i < 5; i++) {
countCalls();
}
return 0;
}
В этом примере calls
инициализируется только один раз и retains свое значение между вызовами функции. Вывод будет следующим:
Эта функция была вызвана 1 раз(а).
Эта функция была вызвана 2 раз(а).
Эта функция была вызвана 3 раз(а).
Эта функция была вызвана 4 раз(а).
Эта функция была вызвана 5 раз(а).
2. Статические члены класса
class MyClass {
public:
static int objectCount;
MyClass() {
objectCount++;
}
};
int MyClass::objectCount = 0;
int main() {
MyClass obj1;
MyClass obj2;
MyClass obj3;
std::cout << "Количество созданных объектов: " << MyClass::objectCount << std::endl;
return 0;
}
Здесь objectCount
shared между всеми экземплярами MyClass
. Вывод будет следующим:
Количество созданных объектов: 3
Класс хранения extern
Ключевое слово extern
используется для декларации глобальной переменной или функции в другом файле.
Файл: globals.cpp
int globalVar = 10;
Файл: main.cpp
#include <iostream>
extern int globalVar; // Декларация globalVar
int main() {
std::cout << "Значение глобальной переменной: " << globalVar << std::endl;
return 0;
}
В этом примере globalVar
определен в globals.cpp
и declared как extern
в main.cpp
. Это позволяет main.cpp
использовать переменную, определенную в другом файле.
Класс хранения mutable
Ключевое слово mutable
позволяет изменять член объекта const.
class Person {
public:
Person(int age) : age(age), cacheValid(false) {}
int getAge() const {
if (!cacheValid) {
cachedAge = heavyComputation();
cacheValid = true;
}
return cachedAge;
}
private:
int age;
mutable int cachedAge;
mutable bool cacheValid;
int heavyComputation() const {
// Моделирование сложной вычислительной задачи
return age;
}
};
int main() {
const Person p(30);
std::cout << p.getAge() << std::endl; // Это разрешено
return 0;
}
В этом примере, даже несмотря на то, что p
является const, мы можем изменять cachedAge
и cacheValid
, так как они помечены как mutable
.
Итог
Давайте подытожим классы хранения, о которых мы узнали, в удобной таблице:
Класс хранения | Назначение |
---|---|
auto | Вывод типа (современный C++) |
register | Подсказка для быстрого доступа (редко используется) |
static | Сохранение значения между вызовами функции или shared между экземплярами класса |
extern | Декларация переменных или функций из других файлов |
mutable | Позволяет изменять в const объектах |
Запомните, понимание классов хранения важно для эффективного управления памятью и управления областью действия ваших переменных. По мере продолжения вашего пути в C++ эти концепции станут для вас второй натурой. Удачи в программировании!
Credits: Image by storyset