C++ 存储类

你好,有抱负的程序员们!今天,我们将踏上一段激动人心的旅程,探索 C++ 存储类的世界。如果你是编程新手,不用担心;我将作为你友好的向导,一步步解释所有内容。让我们开始吧!

C++ Storage Classes

什么是存储类?

在我们具体讨论之前,让我们先了解一下存储类是什么。在 C++ 中,存储类定义了变量和函数在程序中的作用域(可见性)和生命周期。它们告诉编译器如何存储变量,是否可以从其他文件访问它,以及它在内存中应该存在多长时间。

现在,让我们详细探索每个存储类。

auto 存储类

C++ 中的 auto 关键字在过去的版本中改变了它的含义。在现代 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 关键字是给编译器的一个提示,表明这个变量将被频繁使用,并且应该保持在 CPU 寄存器中以获得更快访问。

#include <iostream>

int main() {
register int counter = 0;

for(int i = 0; i < 1000000; i++) {
counter++;
}

std::cout << "Counter: " << counter << std::endl;
return 0;
}

在这个例子中,我们建议编译器 counter 应该保持在寄存器中。然而,现代编译器通常足够智能,能够自己进行这些优化,所以 register 在实际中很少使用。

static 存储类

static 关键字根据其使用的位置有不同的含义:

1. 静态局部变量

#include <iostream>

void countCalls() {
static int calls = 0;
calls++;
std::cout << "This function has been called " << calls << " times." << std::endl;
}

int main() {
for(int i = 0; i < 5; i++) {
countCalls();
}
return 0;
}

在这个例子中,calls 只被初始化一次,并在函数调用之间保持其值。输出将是:

This function has been called 1 times.
This function has been called 2 times.
This function has been called 3 times.
This function has been called 4 times.
This function has been called 5 times.

2. 静态类成员

class MyClass {
public:
static int objectCount;

MyClass() {
objectCount++;
}
};

int MyClass::objectCount = 0;

int main() {
MyClass obj1;
MyClass obj2;
MyClass obj3;

std::cout << "Number of objects created: " << MyClass::objectCount << std::endl;
return 0;
}

在这里,objectCount 在所有 MyClass 实例之间共享。输出将是:

Number of objects created: 3

extern 存储类

extern 关键字用于在另一个文件中声明全局变量或函数。

文件:globals.cpp

int globalVar = 10;

文件:main.cpp

#include <iostream>

extern int globalVar;  // 声明 globalVar

int main() {
std::cout << "Global variable value: " << globalVar << std::endl;
return 0;
}

在这个例子中,globalVarglobals.cpp 中定义,并在 main.cpp 中声明为 extern。这使得 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,我们仍然可以修改 cachedAgecacheValid,因为它们被标记为 mutable

总结

让我们总结一下我们学到的存储类,并在一个方便的表格中展示:

存储类 目的
auto 类型推断(现代 C++)
register 提示更快访问(很少使用)
static 在函数调用之间保持值或在类实例之间共享
extern 声明其他文件中的变量或函数
mutable 允许 const 对象中的成员被修改

记住,理解存储类对于有效地管理内存和控制变量的作用域至关重要。随着你继续你的 C++ 之旅,你会发现这些概念变得习以为常。祝你编程愉快!

Credits: Image by storyset