类内静态

Posted by danielh on October 20, 2025

1. 类中静态变量/函数有什么作用,举简单例子说明一下

类中静态变量和函数的主要作用是实现类级别的共享,而不是实例级别的。下面用简单例子说明:

1. 静态变量(类变量)

计数器功能

class Student {
public:
    static int count;  // 静态变量 - 统计学生总数
    
    Student() {
        count++;  // 每创建一个学生,计数器+1
    }
};

// 类外定义静态变量
int Student::count = 0;

int main() {
    Student s1, s2, s3;
    cout << "学生总数: " << Student::count;  // 输出: 3
    return 0;
}

共享配置

class Config {
public:
    static string schoolName;  // 所有学生共享的学校名
};

string Config::schoolName = "第一中学";

int main() {
    cout << Config::schoolName;  // 输出: 第一中学
    return 0;
}

2. 静态函数

工具函数

class MathUtils {
public:
    static int add(int a, int b) {  // 静态函数
        return a + b;
    }
    
    static double getPI() {         // 静态函数
        return 3.14159;
    }
};

int main() {
    // 直接通过类名调用,不需要创建对象
    cout << MathUtils::add(5, 3);    // 输出: 8
    cout << MathUtils::getPI();      // 输出: 3.14159
    return 0;
}

访问静态变量

class BankAccount {
private:
    static double interestRate;  // 私有静态变量
    
public:
    static void setInterestRate(double rate) {  // 静态函数可以访问静态变量
        interestRate = rate;
    }
    
    static double getInterestRate() {
        return interestRate;
    }
};

double BankAccount::interestRate = 0.03;

int main() {
    cout << "当前利率: " << BankAccount::getInterestRate();  // 输出: 0.03
    BankAccount::setInterestRate(0.035);
    cout << "新利率: " << BankAccount::getInterestRate();    // 输出: 0.035
    return 0;
}

3. 综合例子

class Car {
public:
    static int totalCars;     // 静态变量 - 汽车总数
    string brand;
    
    Car(string b) : brand(b) {
        totalCars++;
    }
    
    // 静态函数
    static int getTotalCars() {
        return totalCars;
    }
    
    static void resetCounter() {
        totalCars = 0;
    }
};

int Car::totalCars = 0;

int main() {
    Car car1("Toyota");
    Car car2("Honda");
    Car car3("BMW");
    
    cout << "总共创建了 " << Car::getTotalCars() << " 辆车";  // 输出: 3
    
    Car::resetCounter();
    cout << "重置后: " << Car::getTotalCars();  // 输出: 0
    
    return 0;
}

主要作用总结:

类型 作用 特点
静态变量 类级别的数据共享 所有对象共享同一份数据
静态函数 类级别的操作 不需要对象就能调用,只能访问静态成员

关键特点:

  • 静态变量:内存中只有一份,所有对象共享
  • 静态函数:通过 类名::函数名() 调用
  • 静态函数:不能访问非静态成员(因为没对象)
  • 适用场景:计数器、配置信息、工具函数、单例模式

2. 静态变量可以在类内类外随意赋值吗

静态变量的赋值是有严格规则的,不能在类内类外随意赋值。以下是详细说明:

1. 静态变量的声明和定义规则

基本规则

class Example {
public:
    static int count;        // 声明静态变量
    static const int MAX = 100;  // 只有静态常量整型可以在类内初始化
};

// 必须在类外定义(分配内存)
int Example::count = 0;      // 正确:类外定义并初始化

// int Example::count = 10;  // 错误:重复定义

2. 不同情况的赋值规则

情况1:普通静态变量

class Counter {
public:
    static int count;  // 只能声明,不能初始化
    
    // static int count = 0;  // 错误:不能在类内初始化普通静态变量
};

// 必须在类外定义和初始化
int Counter::count = 0;  // 正确

void test() {
    Counter::count = 100;  // 正确:可以在任何地方修改
    Counter::count++;      // 正确:可以修改
}

情况2:静态常量整型(特殊规则)

class Constants {
public:
    static const int MAX_SIZE = 100;     // 正确:整型常量可以在类内初始化
    static const short SHORT_MAX = 255;  // 正确:整型家族都可以
    static const char CHAR_MAX = 127;    // 正确
    static const bool DEBUG = true;      // 正确:bool也是整型
    
    // static const double PI = 3.14;    // 错误:非整型不能在类内初始化
};

// 对于ODR-used的静态常量整型,仍然需要在类外定义(但不初始化)
const int Constants::MAX_SIZE;  // 不需要再赋值

情况3:静态常量非整型

class MathConstants {
public:
    static const double PI;    // 只能声明
    static const string NAME;  // 只能声明
};

// 必须在类外定义和初始化
const double MathConstants::PI = 3.14159;
const string MathConstants::NAME = "Math";

3. C++17 内联静态变量(新特性)

C++17 允许使用 inline 在类内直接初始化:

class ModernExample {
public:
    inline static int count = 0;           // C++17:正确
    inline static const double PI = 3.14;  // C++17:正确
    inline static vector<int> data = {1, 2, 3};  // C++17:正确
    
    // 使用内联静态变量后,不需要类外定义
};

int main() {
    ModernExample::count = 100;  // 正确:可以修改
    // ModernExample::PI = 3.15; // 错误:const 不能修改
    return 0;
}

4. 访问控制的影响

class AccessExample {
private:
    static int privateVar;    // 私有静态变量
    static const int PRIVATE_CONST = 50;
    
public:
    static int publicVar;     // 公有静态变量
    static const int PUBLIC_CONST = 100;
    
    static void setPrivate(int value) {
        privateVar = value;  // 类内成员函数可以访问私有静态变量
    }
};

int AccessExample::privateVar = 0;
int AccessExample::publicVar = 0;

int main() {
    AccessExample::publicVar = 200;  // 正确:公有可以外部访问
    // AccessExample::privateVar = 300;  // 错误:私有不能外部访问
    
    AccessExample::setPrivate(300);  // 正确:通过公有函数访问私有变量
    return 0;
}

5. 综合示例

#include <iostream>
#include <string>
using namespace std;

class Car {
private:
    static int nextId;           // 私有静态变量
    
public:
    static int totalCars;        // 公有静态变量
    static const int MAX_CARS = 1000;  // 公有静态常量
    
    int id;
    string brand;
    
    Car(string b) : brand(b) {
        id = nextId++;          // 使用私有静态变量
        totalCars++;            // 使用公有静态变量
    }
    
    static void resetCounter() {
        nextId = 1;
        totalCars = 0;
    }
    
    static int getNextId() {
        return nextId;
    }
};

// 类外定义(必须在全局作用域)
int Car::nextId = 1;
int Car::totalCars = 0;

int main() {
    cout << "最大车辆数: " << Car::MAX_CARS << endl;  // 正确:访问常量
    
    Car car1("Toyota");
    Car car2("Honda");
    
    cout << "总车辆数: " << Car::totalCars << endl;    // 正确:访问公有静态变量
    cout << "下一个ID: " << Car::getNextId() << endl;  // 正确:通过函数访问私有
    
    Car::totalCars = 5;        // 正确:修改公有静态变量
    // Car::nextId = 10;       // 错误:不能直接访问私有静态变量
    
    return 0;
}

总结

类型 类内初始化 类外定义 可修改性
普通静态变量 ❌ (C++17前)
静态常量整型 ⚠️(需要时)
静态常量非整型 ❌ (C++17前)
内联静态变量 (C++17) 取决于const

关键点:

  • 普通静态变量需要在类外定义(分配内存)
  • 只有静态常量整型可以在类内初始化
  • C++17 的 inline static 打破了这些限制
  • 访问控制(public/private)影响外部访问权限

3. 类内成员函数都可以访问类内静态成员变量吗

是的,类内的所有成员函数都可以访问类内的静态成员变量,无论这些成员函数是普通成员函数、静态成员函数、const成员函数,还是构造函数、析构函数。

1. 普通成员函数访问静态变量

class Example {
private:
    static int count;        // 静态变量
    int id;                  // 普通成员变量
    
public:
    Example() {
        id = ++count;        // 构造函数访问静态变量
        cout << "创建对象,ID: " << id << endl;
    }
    
    void display() {         // 普通成员函数
        cout << "对象ID: " << id << ", 总数: " << count << endl;
    }
    
    void increment() {       // 普通成员函数修改静态变量
        count++;
    }
};

int Example::count = 0;

int main() {
    Example e1, e2;
    e1.display();  // 输出: 对象ID: 1, 总数: 2
    e2.increment();
    e2.display();  // 输出: 对象ID: 2, 总数: 3
    return 0;
}

2. 静态成员函数访问静态变量

class Bank {
private:
    static double interestRate;  // 静态变量
    static int totalAccounts;    // 静态变量
    
public:
    // 静态成员函数只能访问静态成员
    static void setInterestRate(double rate) {
        interestRate = rate;
    }
    
    static double getInterestRate() {
        return interestRate;
    }
    
    static int getTotalAccounts() {
        return totalAccounts;
    }
    
    Bank() {
        totalAccounts++;  // 构造函数访问静态变量
    }
};

double Bank::interestRate = 0.03;
int Bank::totalAccounts = 0;

int main() {
    Bank b1, b2, b3;
    cout << "总账户数: " << Bank::getTotalAccounts() << endl;  // 输出: 3
    Bank::setInterestRate(0.035);
    cout << "利率: " << Bank::getInterestRate() << endl;       // 输出: 0.035
    return 0;
}

3. const成员函数访问静态变量

class Student {
private:
    static int nextId;
    static int totalStudents;
    int id;
    string name;
    
public:
    Student(string n) : name(n) {
        id = nextId++;
        totalStudents++;
    }
    
    // const成员函数可以读取静态变量
    void display() const {
        cout << "学生ID: " << id << ", 姓名: " << name << endl;
        cout << "总学生数: " << totalStudents << endl;  // 正确:读取静态变量
    }
    
    // const成员函数不能修改普通成员变量,但可以读取静态变量
    void showInfo() const {
        // id = 100;  // 错误:const函数不能修改普通成员变量
        cout << "下一个可用ID: " << nextId << endl;  // 正确:读取静态变量
    }
};

int Student::nextId = 1;
int Student::totalStudents = 0;

4. 各种成员函数综合示例

#include <iostream>
#include <string>
using namespace std;

class Car {
private:
    static int totalCars;        // 静态变量
    static int nextId;
    int id;
    string brand;
    double price;
    
public:
    // 构造函数
    Car(string b, double p) : brand(b), price(p) {
        id = nextId++;
        totalCars++;
        cout << "创建汽车 ID: " << id << endl;
    }
    
    // 析构函数
    ~Car() {
        totalCars--;
        cout << "销毁汽车 ID: " << id << endl;
    }
    
    // 普通成员函数
    void display() {
        cout << "ID: " << id << ", 品牌: " << brand << ", 价格: " << price << endl;
        cout << "当前总车辆: " << totalCars << endl;
    }
    
    // const成员函数
    void showInfo() const {
        cout << "车辆 " << id << " - " << brand << endl;
        cout << "市场上总车辆: " << totalCars << endl;  // 可以读取静态变量
    }
    
    // 静态成员函数
    static int getTotalCars() {
        return totalCars;
    }
    
    static void resetCounter() {
        totalCars = 0;
        nextId = 1;
    }
    
    // 修改价格的普通函数
    void setPrice(double newPrice) {
        price = newPrice;
        cout << "修改价格,当前总车辆数: " << totalCars << endl;
    }
};

int Car::totalCars = 0;
int Car::nextId = 1;

int main() {
    Car car1("Toyota", 200000);
    Car car2("Honda", 180000);
    
    car1.display();      // 普通成员函数访问静态变量
    car2.showInfo();     // const成员函数访问静态变量
    
    cout << "通过静态函数访问: " << Car::getTotalCars() << endl;
    
    car1.setPrice(190000);  // 修改价格时也访问了静态变量
    
    return 0;
}

5. 访问控制的影响

class AccessExample {
private:
    static int privateStatic;   // 私有静态变量
    int privateNormal;          // 私有普通变量
    
public:
    static int publicStatic;    // 公有静态变量
    
    // 所有成员函数都可以访问私有静态变量
    void normalFunction() {
        privateStatic = 100;    // 正确:可以访问私有静态
        privateNormal = 50;     // 正确:可以访问私有普通
    }
    
    static void staticFunction() {
        privateStatic = 200;    // 正确:静态函数可以访问私有静态
        // privateNormal = 60;  // 错误:静态函数不能访问普通成员
    }
    
    void constFunction() const {
        // privateStatic = 300; // 错误:const函数不能修改任何变量
        int temp = privateStatic;  // 正确:可以读取静态变量
        // privateNormal = 70;  // 错误:const函数不能修改普通成员
    }
};

int AccessExample::privateStatic = 0;
int AccessExample::publicStatic = 0;

总结

函数类型 能否访问静态变量 能否修改静态变量 说明
普通成员函数 完全访问权限
静态成员函数 只能访问静态成员
const成员函数 只能读取,不能修改
构造函数 完全访问权限
析构函数 完全访问权限

关键点:

  • 所有成员函数都可以访问静态成员变量
  • 静态函数只能访问静态成员,不能访问普通成员
  • const函数可以读取静态变量,但不能修改
  • 🔒 访问控制(public/private)影响的是类外访问,类内所有函数都可以访问所有成员

4. 类内静态成员函数可以访问类内成员变量吗

不可以,类内的静态成员函数不能访问类内的普通成员变量。

静态成员函数只能访问静态成员(静态变量和静态函数),不能访问普通成员变量。

1. 基本规则演示

class Example {
private:
    int normalVar;          // 普通成员变量
    static int staticVar;   // 静态成员变量
    
public:
    Example(int val) : normalVar(val) {}
    
    // 静态成员函数
    static void staticFunction() {
        staticVar = 100;    // ✅ 正确:可以访问静态变量
        // normalVar = 50;  // ❌ 错误:不能访问普通成员变量
    }
    
    // 普通成员函数
    void normalFunction() {
        normalVar = 50;     // ✅ 正确:可以访问普通成员变量
        staticVar = 100;    // ✅ 正确:可以访问静态变量
    }
};

int Example::staticVar = 0;

2. 为什么不能访问?

class Student {
private:
    string name;           // 普通成员变量 - 属于对象
    int age;               // 普通成员变量 - 属于对象
    static int totalStudents;  // 静态变量 - 属于类
    
public:
    Student(string n, int a) : name(n), age(a) {
        totalStudents++;
    }
    
    // 静态函数 - 没有this指针
    static void printTotal() {
        cout << "总学生数: " << totalStudents << endl;  // ✅ 正确
        
        // ❌ 以下都是错误的:
        // cout << "姓名: " << name << endl;    // 错误:哪个对象的name?
        // cout << "年龄: " << age << endl;     // 错误:哪个对象的age?
        // this->name = "Tom";                  // 错误:静态函数没有this指针
    }
    
    // 普通函数 - 有this指针
    void printInfo() {
        cout << "姓名: " << name << endl;       // ✅ 正确:this->name
        cout << "年龄: " << age << endl;        // ✅ 正确:this->age
        cout << "总数: " << totalStudents << endl; // ✅ 正确
    }
};

int Student::totalStudents = 0;

3. 实际例子说明

#include <iostream>
#include <string>
using namespace std;

class Car {
private:
    string brand;           // 普通成员变量
    double price;           // 普通成员变量
    static int totalCars;   // 静态成员变量
    static double totalValue; // 静态成员变量
    
public:
    Car(string b, double p) : brand(b), price(p) {
        totalCars++;
        totalValue += price;
    }
    
    ~Car() {
        totalCars--;
        totalValue -= price;
    }
    
    // 静态函数 - 只能访问静态成员
    static void showStatistics() {
        cout << "=== 汽车统计 ===" << endl;
        cout << "总数量: " << totalCars << endl;        // ✅ 正确
        cout << "总价值: " << totalValue << endl;       // ✅ 正确
        
        // ❌ 以下都是错误的:
        // cout << "品牌: " << brand << endl;           // 错误
        // cout << "价格: " << price << endl;           // 错误
        // cout << "平均价格: " << totalValue / totalCars << endl; // ✅ 正确(用静态变量计算)
    }
    
    // 普通函数 - 可以访问所有成员
    void showCarInfo() {
        cout << "品牌: " << brand << endl;              // ✅ 正确
        cout << "价格: " << price << endl;              // ✅ 正确
        cout << "总数量: " << totalCars << endl;        // ✅ 正确
    }
    
    // 静态函数返回静态变量
    static int getTotalCars() {
        return totalCars;   // ✅ 正确
    }
    
    static double getAveragePrice() {
        if (totalCars > 0) {
            return totalValue / totalCars;  // ✅ 正确:用静态变量计算
        }
        return 0;
    }
};

int Car::totalCars = 0;
double Car::totalValue = 0;

int main() {
    Car::showStatistics();  // 不需要对象就能调用静态函数
    
    Car car1("Toyota", 200000);
    Car car2("Honda", 180000);
    
    Car::showStatistics();  // 输出统计信息
    
    car1.showCarInfo();     // 输出具体车辆信息
    
    cout << "平均价格: " << Car::getAveragePrice() << endl;
    
    return 0;
}

4. 解决方案:如果需要访问普通成员

class BankAccount {
private:
    string accountNumber;   // 普通成员变量
    double balance;         // 普通成员变量
    static double interestRate;  // 静态变量
    
public:
    BankAccount(string accNo, double bal) : accountNumber(accNo), balance(bal) {}
    
    // 静态函数 - 无法直接访问普通成员,但可以通过参数传递
    static void applyInterest(BankAccount& account) {
        // 通过传入的对象引用访问其普通成员
        account.balance += account.balance * interestRate;
        cout << "为账户 " << account.accountNumber << " 应用利息" << endl;
    }
    
    // 静态函数 - 通过指针访问
    static void applyInterest(BankAccount* account) {
        if (account) {
            account->balance += account->balance * interestRate;
        }
    }
    
    // 普通函数调用静态函数
    void applyMyInterest() {
        BankAccount::applyInterest(*this);  // 传递当前对象
    }
    
    void display() {
        cout << "账户: " << accountNumber << ", 余额: " << balance << endl;
    }
    
    static void setInterestRate(double rate) {
        interestRate = rate;
    }
};

double BankAccount::interestRate = 0.03;

int main() {
    BankAccount acc1("12345", 1000);
    BankAccount acc2("67890", 2000);
    
    // 方式1:通过静态函数传入对象
    BankAccount::applyInterest(acc1);
    acc1.display();
    
    // 方式2:通过普通函数调用静态函数
    acc2.applyMyInterest();
    acc2.display();
    
    return 0;
}

5. 访问控制的影响

class AccessExample {
private:
    int privateNormal;          // 私有普通成员
    static int privateStatic;   // 私有静态成员
    
public:
    int publicNormal;           // 公有普通成员
    static int publicStatic;    // 公有静态成员
    
    // 静态函数
    static void staticFunction() {
        privateStatic = 100;    // ✅ 正确:可以访问私有静态
        publicStatic = 200;     // ✅ 正确:可以访问公有静态
        
        // ❌ 以下都是错误的:
        // privateNormal = 50;  // 错误:不能访问普通成员(即使是公有的)
        // publicNormal = 60;   // 错误:不能访问普通成员(即使是公有的)
    }
};

int AccessExample::privateStatic = 0;
int AccessExample::publicStatic = 0;

总结

函数类型 可以访问 不能访问 原因
静态成员函数 静态变量、静态函数 普通成员变量、普通成员函数 没有this指针
普通成员函数 所有成员(静态+普通) 无限制 有this指针

关键原因:

  • 静态函数属于,不依赖于任何对象
  • 静态函数没有this指针
  • 普通成员变量属于对象,需要this指针来访问
  • 静态函数在对象创建之前就可以调用

使用场景:

  • 静态函数适合:工具函数、工厂方法、访问静态数据
  • 普通函数适合:操作对象特定数据、需要访问对象状态的操作