静态方法和变量
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 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);静态方法适合用于不需要对象状态的实用函数、创建对象的工厂方法,或访问静态数据。由于不需要对象实例,你可以使用类名和作用域解析运算符来调用它们:ClassName::methodName()。
挑战
简单让我们构建一个唯一 ID 生成器系统,演示静态方法和变量如何协同工作,在不需要对象实例的情况下提供类级功能。
你将创建两个文件来整理代码:
IDGenerator.h:定义一个生成连续唯一 ID 的IDGenerator类。你的类应包含:- 一个私有静态成员
nextId,用于记录下一个要分配的 ID(初始值为1000) - 一个私有静态成员
prefix(字符串),用于存储所有 ID 的可自定义前缀 - 一个静态方法
setPrefix(const std::string& p),用于更改前缀 - 一个静态方法
getNextId(),用于返回由前缀和当前 ID 编号组成的字符串,然后递增nextId,供下次调用使用 - 一个静态方法
peekNextId(),用于返回下一个 ID 的值,但不递增计数器 - 一个静态方法
getGeneratedCount(),用于返回已生成的 ID 数量(提示:根据初始值和当前的nextId计算) - 一个静态方法
reset(),用于将nextId重置为1000
记得在类定义之后,在类的外部定义静态成员。将
prefix初始化为"ID-"。- 一个私有静态成员
main.cpp:演示如何使用类名调用静态方法,而不创建任何对象。从输入中读取自定义前缀,然后:- 使用
peekNextId()打印"Peek: <peeked_id>" - 使用
getNextId()生成三个 ID,并将每个 ID 打印为"Generated: <id>" - 打印
"Count: <count>",显示已生成的 ID 数量 - 使用输入值通过
setPrefix()更改前缀 - 再生成两个 ID,并将每个 ID 打印为
"Generated: <id>" - 再次打印
"Count: <count>" - 调用
reset() - 打印
"After reset - Peek: <peeked_id>" - 打印
"After reset - Count: <count>"
- 使用
注意,你从未创建 IDGenerator 对象:所有方法都使用 IDGenerator::methodName() 直接通过类调用。这是静态方法的关键特征:它们属于类本身,而不属于任何特定实例。
在头文件中包含 <string> 和 <iostream>,并且别忘了添加头文件保护。
亲手试试
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// 从输入中读取自定义前缀
string customPrefix;
cin >> customPrefix;
// TODO: 使用 peekNextId() 打印 "Peek: <peeked_id>"
// TODO: 使用 getNextId() 生成 3 个 ID,并将每个 ID 打印为 "Generated: <id>"
// TODO: 打印 "Count: <count>",显示已生成的 ID 数量
// TODO: 使用 setPrefix() 将前缀改为输入的值
// TODO: 再生成 2 个 ID,并将每个 ID 打印为 "Generated: <id>"
// TODO: 再次打印 "Count: <count>"
// TODO: 调用 reset()
// TODO: 打印 "After reset - Peek: <peeked_id>"
// TODO: 打印 "After reset - Count: <count>"
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器