Menu
CoddyTech

静态方法和变量

本课属于 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()。

challenge icon

挑战

简单

让我们构建一个唯一 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;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器