Menu
CoddyTech

实例成员与静态成员

本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 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--;          // 销毁玩家时递减
    }
};

关键区别:实例成员通过对象访问,而静态成员可以直接通过类名访问。你可以把实例成员理解为“每个对象一份”,把静态成员理解为“每个类一份”。

实例成员静态成员
每个对象都独有所有对象共享
创建对象时创建在创建任何对象之前就存在
通过对象访问:player.health通过类访问:Player::playerCount

静态成员适用于计数器、配置值,或逻辑上属于类而非单个对象的任何数据。

challenge icon

挑战

简单

让我们构建一个产品库存系统,使用实例成员和静态成员跟踪单个产品的详细信息以及整体库存统计数据。

你将创建两个文件来组织代码:

  • Product.h:定义一个管理单个产品并跟踪整体库存数据的 Product 类。你的类应包含:
    • 实例成员:name(字符串)和 price(double),每个产品各不相同
    • 一个静态成员 totalProducts,用于统计当前存在的产品数量
    • 一个静态成员 totalValue,用于跟踪所有产品的总价
    • 一个构造函数,接收名称和价格,初始化实例成员,并更新两个静态计数器(增加数量,将价格加到总价中)
    • 一个析构函数,在产品被移除时更新静态计数器(减少数量,从总价中减去价格)
    • 一个 getInfo() 方法,返回格式为 "<name>: $<price>" 的字符串
    • 一个静态方法 getInventoryStats(),返回字符串:"Products: <count>, Total Value: $<value>"
  • main.cpp:演示静态成员如何在所有对象之间共享,而实例成员如何保持各自独立。从输入中读取两个产品名称及其价格(name1、price1、name2、price2:每项各占一行),然后:
    • 使用类名打印初始库存统计数据:Product::getInventoryStats()
    • 用花括号创建一个作用域代码块,并在其中创建一个名称和价格取自第一组输入的 Product。打印它的信息和当前库存统计数据。
    • 代码块结束后(第一个产品被销毁),打印 "After first scope:",然后打印库存统计数据
    • 使用第二组名称和价格创建另一个 Product。打印它的信息和库存统计数据。
    • 创建第三个 Product,名称为 "Bonus",价格为 5.00。打印最终库存统计数据。

记得在类定义之后,在头文件中定义类外的静态成员。使用 <iomanip> 中的 std::fixed 和 std::setprecision(2),将价格格式化为保留两位小数。

在 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: 用花括号创建一个作用域块
    // 在代码块内:
    //   用 name1 和 price1 创建一个 Product 对象
    //   使用 getInfo() 输出该对象的信息
    //   输出当前库存统计信息
    
    // TODO: 代码块结束后,输出 "After first scope:"
    // 然后输出库存统计信息
    
    // TODO: 用 name2 和 price2 再创建一个 Product 对象
    // 输出该对象的信息和库存统计信息
    
    // TODO: 创建第三个 Product 对象,名称为 "Bonus",价格为 5.00
    // 打印最终的库存统计信息
    
    return 0;
}
quiz icon自我测试

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

面向对象编程中的所有课

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