C++ 类 静态成员
1. 静态成员的概念
有时候类希望它的成员和类本身直接相关,而不是与类的各个对象保持关联。比如,一个银行账户类可能需要一个数据成员来表示当前的基准利率。在此例中,希望利率与类关联,而非与每个对象关联。从实现效率上看,没必要为每个对象都存储利率信息。更重的一点,一旦利率浮动,希望所有对象都能使用新值。对于这种成员,类将其声明为静态成员。
静态成员可以是可以是数据成员和函数成员,数据成员可以是常量、引用、指针、类类型等。静态成员的访问权限可以是public或private的。
2. 静态成员的声明
通过在成员的声明前加上关键字static将其声明为静态成员,与类关联在一起。
代码示例:
class Account
{
public:
void calculate() { amount += amount * interestRate; }
static double getRate() {return interestRate; }
static void setRate(double);
private:
string owner;
double amount;
static double interestRate;
static double initRate();
}
类的静态成员存在于任何对象之外,因此对象中不包含任何与静态成员有关的数据。每个Account对象只包含owner和amount两个数据成员。
类似的,静态成员函数中也不能与任何对象绑定到一起,它们不包含this指针。
3. 静态成员的定义
3.1 静态成员函数的定义
和其他成员函数一样,静态成员函数即可以在类的内部定义,也可以在类的外部定义。在类的外部定义时,不能重复static关键字,static关键字只出现在类的内部。
void Account::setRate(double r)
{
intersetRate = r;
}
3.2 静态数据成员的定义
因为静态数据成员不属于类的任何一个对象,所以并不是在创建类的对象时被定义的,也就是说它不是在构造函数中被初始化的。一般来说,不能在类的内部初始化静态成员,必须在类的外部定义和初始化每个静态数据成员。
在类的外部定义静态数据成员的方法和在类外部定义成员函数差不多,需要指定成员类型名,然后时类名、作用域运算符以及成员数据自己的名字。
double Account::interestRate = initRate();
这条语句中,类名之后的部分都属于类的作用域之内,因此可直接使用initRate()函数。
和全局变量类似,静态数据成员在任何函数之外被定义。一旦被定义,就将一直存在于程序的整个生命周期中。
一个静态数据成员只能定义一次。要想确保静态数据成员只被定义一次,最好的办法是把静态数据成员的定义与其他非内联函数的定义放在同一文件中
3.3静态数据成员的类内初始化
通常情况下,类的静态数据成员不应该在类内初始化。然而以下两种情况例外:
1、可以为const整型类型的静态数据成员提供类内初始值。
2、当静态成员是constexpr字面值类型时,必须提供类内初始值。(这里是否必须是整形有待验证确认)
因为constexpr字面值类型的静态数据成员是常量表达式,因此它们能够用于需要使用常量表达式的地方。例如可以用一个constexpr类型的静态数据成员来指定数组的大小。
class Account
{
public:
static double getRate() {return interestRate; }
static void setRate(double);
private:
static constexpr int period = 30;
double dailtTbl[period];
}
4. 使用类的静态成员
4.1 使用作用域运算符直接访问静态成员
double r = Account::getRate();
4.2 通过类的对象、引用或指针访问静态成员
虽然静态成员不属于类的某个对象,但仍可以使用类的对象、引用或指针来访问静态成员。
Account ac1;
Account *pac1 = &ac1;
double r;
r = ac1.getRate();
r = pac1->getRate();
4.3 在成员函数中直接使用静态成员
class Account
{
public:
void calculate() { amount += amount * interestRate; }
private:
static double interestRate;
}