7.6类的静态成员

  • 声明静态成员 我们通过在成员声明前加上关键字static使得其与类关联在一起,静态成员可以是public或者private的,静态数据成员的类型可以是常量、引用、指针、类类型。
class Account
{
 public:
  static double rate() {return interestRate; }
  static void rate (double);
 private:
  static double interestRate;
  static double initRate();
};

类的静态成员存在任何对象之外,对象中不包含任何与静态成员有关的数据。因此只存在一个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关键字,其只能出现在类内声明中。

静态数据成员不属于类的任何一个对象,所以它们不是在创建类时被定义的,不是由构造函数初始化的。一般,不能在类内初始化静态成员,必须在类外部定义和初始化。

double Account::interestRate = initRate();//interestRate的定义也可以访问类的私有成员
  • 静态成员的类内初始化

一般,类的静态成员不在类内进行初始化。然而,可以用const整数类型为静态成员提供初始值,不过静态成员必须是constexpr类型的。初始值必须是常量表达式。

class Account
{
 public:
  static double rate() { return interestRate; }
  static void rate(double);
 private:
  static constexpr int period = 30;
  double daily_tbl[period];
};

如果静态成员应用场景仅在编译器可以直接替换它的值的情况下,则一个初始化的constconstexpr不需要分别定义。相反,则必须要有一条定于语句。如果在类内定义了一个初始值,则成员的定义不能在指定一个初始值了。即使一个常量静态数据成员在类内部被初始化了,也应该在类的外部定义一下该成员。

  • 特有的适用场景

静态成员独立于任何类的对象。

class Bar
{
 public:
  //...
 private:
  static Bar mem1;//正确:静态成员可以是不完全类型
  Bar *men2;//正确:指针可以是不完全类型
  Bar men3;//错误:数据成员必须是完全类型
};

静态成员可以做默认实参。非静态成员不能做默认实参,因为它的值属于对象的一部分,无法真正提供一个对象以便获取成员的值,引发错误。

class Screen
{
 public:
  Screen& clear(char = background);
 private:
  static const char background;
};