class Account {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
};
声明类静态成员
- 通过在成员声明前加上
static
关键字,可以将其与类关联在一起。 - 静态成员可以是
public
,private
的。 - 静态数据成员的类型可以是常量、引用、指针、类类型等。
- 静态成员存在于任何对象之外,对象中不包含任何与静态数据成员相关的数据。
- 静态成员函数也不与任何对象绑定在一起,它们不包含
this
指针,作为结果静态成员函数不能声明成const
的,也不能在静态成员函数体内使用this
指针。
使用类的静态成员
可以使用作用域运算符直接访问静态成员:
double r;
r = Account::rate();
虽然静态成员属于类的某个对象,但是我们仍然可以使用类的对象、引用或者引用来访问静态成员。
Account ac1;
Account *ac2 = &ac1;
r = ac1.rate();
r = ac2->rate();
成员函数内部不用通过作用域运算符就能直接使用静态成员:
class Account {
public:
void calculate() { amount += amount * interestRate; }
};
定义静态成员
可以在类的内部也可以在类的外部定义静态成员函数,当在累的外部定义静态成员时,不能重复 static
关键字,该关键字只出现在类内部的声明语句。
因为静态成员不属于类的任何一个对象,所以它们并不是创建类的对象时被定义的,也就是说它们不是由类的构造函数初始化的。
不能在类的内部初始化静态成员,而应该也必须在类的外部定义和初始化每个静态成员,静态数据成员只能被定义一次。
类外定义静态数据成员需要指明其所属的类:
double Account::interestRate = initRate();
这条语句定义了 interestRate
对象,该对象属于 Account
,从类名开始这条定于语句的剩余部分都是位于类的作用域之内,因此可以直接使用 initRate
函数。
通常是将静态数据成员的定义和其它非内联函数的定义放在同一个文件之中。
静态成员的类内初始化
通常情况下类的静态成员不应该在类内初始化,然而可以为静态成员提供 const 整数类型的类内初始值,要求静态成员必须是字面值常量类型的constexpr。
初始值必须是常量表达式,因为这些成员本身就是常量表达式。
可以使用一个初始化了的静态数据成员指定数组成员的维度。
class Account {
public:
static double rate() { return interestRate; }
static void rate(double);
private:
static constexpr int period = 30;
double daily_tbl[period];
};
如果 period
的唯一用途是定义 daily_tbl
的维度,则不需要在 Account
类外面专门定义 period
,但是如果把 Account::period
传递给一个 const int&
函数时,就必须定义 period
。
如果在类的内部提供了一个初始值,则成员的定义不能再指定一个初始值了。
一般即使一个常量静态数据成员在类内部被初始化了,通常情况下也应该在类的外部定义一下这个成员。
静态成员能够应用于一些场景,而普通成员不能
静态成员可以是不完全类型,特别的,静态数据成员的类型可以就是它所属的类类型,而非静态成员则不能,只能声明成它所属类的指针或者引用:
class Bar {
public:
//...
private:
static Bar mem1;
Bar *mem2;
};
可以使用静态成员作为默认实参,非静态数据成员则不能作默认实参。
class Screen {
public:
Screen &clear(char = bkground);
private:
static const char bkground;
};