类的静态成员

由static关键字修饰的类成员(数据成员和成员函数)叫做静态成员。 静态成员不是对象的一部分,而是类的一部分,这是静态成员和普通成员之间最本质的区别。

声明静态成员

 通过在成员的声明之前加上关键字static使得其与类关联在一起。和其他成员一样,静态成员可以是public的或private的。静态数据成员的类型可以是常量、引用、指针、类类型等。
引用《C++ Primer(第五版)》中的一段代码
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类关联,被所有Account对象共享。
类似的,静态成员函数也不与任何对象绑定在一起,它们不包含this指针。作为结果,静态成员函数不能声明成const的,而且我们也不能再static函数体内使用this指针。这一限制既适用于this的显式使用,也对调用非静态成员的隐式使用有效。

使用静态成员

可以用作用域运算符直接访问静态成员:
double r;
r = Account::rate();
double Account::enterestRate = 3.24;
虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、应用或指针来访问静态成员:
Account ac1;
Account *ac2 = &ac1;
r = ac1.rate();//通过Account的对象或引用
r = ac2->rate();//通过指向Account对象的指针
普通成员函数不用通过作用域运算符就能直接使用静态成员,而静态成员函数无法直接访问普通数据成员(可以通过对象名简介访问),因为静态成员函数属于类而不属于对象,没有this指针,普通成员函数的实体又仅存在于对象中。

定义静态成员

和其他成员函数一样,我们既可以在类的内部也可以在类的外部定义静态成员函数。当在类的外部定义静态成员时,不能重复static关键字,该关键字只出现在类的内部的声明语句:
void Account::rate(double newRate) {
	interestRate = newRate;
}
因为静态数据成员不属于类的任何一个对象,所以它们并不是在创建类的对象时被定义的。这意味着它们不是由类的构造函数初始化的。而且一般来说,我们不能在类的内部初始化静态成员。相反的,必须在类的外部定义和初始化每个静态成员。和其他对象一样,一个静态数据成员只能定义一次。
类似于全局变量,静态数据成员定义在任何函数之外。因此它一旦被定义,就将一直存在于程序的整个生命周期中。
double Account::interestRate = initRate();//定义并初始化一个静态数据成员
这条语句从类名开始,剩余的部分都位于类的作用域之内,因此可以直接使用initRate函数。虽然initRate是私有的,我们也能用它初始化interestRate。和其他成员的定义一样,interestRate的定义也可以访问类的私有成员(需满足静态条件)。
静态成员也可以类内初始化,但必须满足一定条件,静态成员的类内初始化有诸多限制,内容繁杂,在C++标准文档中可以查阅。

静态成员的某些应用场景

静态成员独立于任何对象,因此在某些非静态数据成员可能非法的场合,静态成员却可以正常地使用。比如,静态数据成员可以是不完全类型。特别的,静态数据成员可以就是它所属的类类型。而非静态数据成员则受到限制,只能声明成它所属类的指针或引用:
class Bar {
public:
	//...
private:
	static Bar mem1;//正确,静态成员可以是不完全类型
	Bar *mem2;//正确
	Bar mem3;//错误,非静态数据成员必须是完全类型
};
静态成员和普通成员的另外一个区别是我们可以使用静态成员作为默认实参:
class Screen {
public:
	Screen& clear(char = bkground);
private:
	static const char bkgroud;
};
非静态数据成员不能作为默认实参,因为它的指本身属于对象的一部分。
本文摘自《C++ Primer(中文版)第五版》,内容有部分改动

你可能感兴趣的:(c/c++,学习笔记)