7.6 类的静态成员
7.6 类的静态成员
声明静态成员
和其他成员一样高,静态成员可以是public的或private的。静态数据成员的类型可以是常量、引用、指针、类类型等。
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();
};
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。因此,每个Account对象将包含两个数据成员:owner和amount。只存在一个interestRate 对象而且它被所有Account对象共享。
类似的,静态成员函数也不与任何对象绑定在一起,它们不包含this指针。作为结果,经静态成员函数不能声明成const的,而且我们也不能在static函数体内使用this指针。这限制既适用于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; }
private:
static double interestRate;
};
定义静态成员
- 定义静态函数成员
和其他的成员函数一样, 我们既可以在类的内部也可以在类的外部定义静态成员函
数。当在类的外部定义静态成员时, 不能重复static关键字, 该关键字只出现在类内部
的声明语句:
class Account {
public:
static void rate(double);
private:
static double interestRate;
};
void Account::rate(double newRate)
{
interestRate = newRate;
}
- 定义静态数据成员
定义时间
因为静态数据成员不属于类的任何一个对象,所以它们并不是在创建类的对象时被定义的。这意味着它们不是由类的构造函数初始化的。
定义位置
而且一般来说, 我们不能在类的内部初始化静态成员。相反的,必须在类的外部定义和初始化每个静态成员。和其他对象一样,一个静态数据成员只能定义一次。类似于全局变量, 静态数据成员定义在任何函数之外。
定义方式
定义静态数据需要指定对象的类型名,然后是类名、作用域运算符以及成员自己的名字:
class Account {
private:
static double interestRate;
static double initRate();
};
// 定义并初始化一个静态成员
// 从类名开始,这条定义语旬的剩余部分就都位于类的作用域之内了。因此,我们可以直接使用initRate函数。
double Account::interestRate = initRate();
静态成员的类内初始化
通常情况下,类的静态成员不应该在类的内部初始化。然而,我们可以为静态成员提供const整数类型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr。
class Account {
public:
static double rate() { return interestRate; }
static void rate(double);
private:
static constexpr int period = 30; // period是常量表达式
double daily_tbl[period];
};
如果在类的内部提供了一个初始值,则成员的定义不能再指定一个初始值了:
// 一个不带初始值的静态成员的定义
constexpr int Account: :period; // 初始f直在类的定义内提供
即使一个常量静态数据成员在类内部被初始化了,通常情况下也应该在类的外部定义一下该成员。
静态成员能用于某些场景, 而普通成员不能
举个例子,静态数据成员可以是不完全类型。特别的, 静态数据成员的类型可以就是它所属的类类型。而非静态数据成员则受到限制,只能声明成它所属类的指针或引用:
class Bar {
public:
// ...
private:
static Bar mem1; // 正确:静态成员可以是不完全类型
Bar *mem2; // 正确:指针成员可以是不完全类型
Bar mem3; // 错误:数据成员必须是完全类型
}
静态成员和普通成员的另外一个区别是我们可以使用静态成员作为默认实参:
class Screen {
public:
// bkground表示一个在类中稍后定义的静态成员
Screen& clear(char = bkground);
private:
static canst char bkground;
};
非静态数据成员不能作为默认实参,因为它的值本身属于对象的一部分,这么做的结果是无法真正提供一个对象以便从巾获取成员的值, 最终将引发错误。
浙公网安备 33010602011771号