如果某些成员从逻辑上来说更应该是与类本身相关联,而不是与类的具体对象相关联,则我们应该把这种成员声明成静态的。
声明静态成员
静态成员可以是public的或private的。静态数据成员的类型可以是常量、引用、指针、类类型等。
using namespace std;
class Acount {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
string owmer;
double amount;
static double interestRate;
static double initRate();
};
类的静态成员存在于任何对象之外,对象中不包含任何静态数据成员有关的数据。因此,每个Acount对象包含两个数据成员:owner和amount.只存在一个interestRate对象而且它被所有Acount对象共享。(这个不太懂)
使用类的静态成员:
使用作用域运算符直接访问静态成员:
double r;
r = Acount::rate();
虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、引用、或指针来访问静态成员:
Acount ac1;
Acount *ac2 = &ac1;
//调用静态成员函数rate()的等价形式
r = ac1.rate(); //通过Acount的对象或引用
r = ac2->rate(); //通过指向Acount对象的指针
成员函数不用通过作用域运算符就能直接使用静态成员:
public:
void calculate() { amount += amount * interestRate; }
private:
static double interestRate;
定义静态成员:和类的所有成员一样,当我们指向类外部的静态成员时,必须指明成员所属的类名。static关键字则只出现在类内部的声明语句中。
void Acount::rate(double newRate)
{
interestRate = newRate;
}
因为静态成员数据不属于类的任何一个对象,所以他们并不是在创建类的对象时被定义的。这意味着它们不是由类的构造函数初始化的。我们一般不再类的内部初始化静态成员,但是必须在类的外部定义和初始化每个静态成员。一个静态数据成员只能被定义一次。静态数据成员定义在任何函数之外,所以一旦它被定义,就将一直存在于程序的整个生命周期中。
定义静态数据成员的方式和在类外部定义成员函数差不多,我们需要指定对象的类型名,然后是类名、作用域运算符以及成员自己的名字。
double Acount::interestRate = initRate();
从类名开始,这条定义语句的剩余部分就都位于类的作用域之内了,因此,我们可以直接使用initRate函数来给interestRate赋值,尽管他是私有的。
带有类内初始值设定项的静态数据成员必须具有不可变的常量整型
static constexpr int peried = 30;
如果一个静态数据成员在类内被提供了一个初始值,则成员的定义不能再指定一个初始值了。
constexpr int Acount::peried;
且即使一个常量静态数据成员在类内部被初始化了,通常情况下也应该在类的外部定义一下该成员。
静态数据成员可以是不完全类型(在类声明之后,完全定义之前),静态数据成员的类型可以就是它所属的类类型。而非静态数据成员只能声明成它的指针或引用。
class Bar {
public:
private:
static Bar mem1; //正确,静态成员可以是不完全类型
Bar *mem2; //正确,指针成员可以是不完全类型
Bar mem3; //错误,非静态数据成员必须是完全类型
};
静态成员可以作为默认实参
class Screen {
public:
Screen& clear(char = bkground);
private:
static const char bkground;
};
静态成员和普通成员的区别主要体现在普通成员与类的对象相关联,是某个具体对象的组成部分;而静态成员不从属于任何具体的对象,它由该类的所有所有对象共享。另外,还有一个细微的区别,静态成员可以作为默认实参,普通成员不行。
除了静态常量成员之外,其他静态成员不能在类的内部初始化,而应该在类的外部给出静态成员的初始值。