关键字static的意思是静态,有3个明显作用:
1)在函数体内,静态变量具有"记忆"功能。即在函数被调用过程中,一个被声明为静态变量的值维持不变。
static局部变量和普通局部变量的区别:static局部变量只被初始化一次,下一次的运算依据上一次的结果值。
2)在模块内,但在函数体外,它的作用域范围是有限制的。static类型的变量,是本地的全局变量。所以,可以被模块内的所有函数访问,不可以被模块外的函数访问。
3)static类型的函数,与普通类型函数的作用域不一样。静态函数的作用域仅在本文件中,只可被模块内的其它函数调用,不能被模块外的其它函数调用。
C++中与类有关的static:
static数据成员特点:
(1)对于非静态数据成员,每个类对象都有自己的复制品;而静态数据成员被当做类的成员。无论有多少个对象,静态数据成员只有一个复制品,由类的所有对象共享访问。
(2)static数据成员存储在全局数据区。定义时要分配内存空间,所以不能在类声明中定义。由于类的所有对象共享,不属于特定的类对象,所以,没有产生类对象时,其作用于可见,即在没有产生类的实例时程序员就可以使用它。
(3)和普通数据成员一样,遵从public,private,protected访问规则。
(4)必须初始化;static成员变量的初始化是在类外。初始化时不带上static的关键字。private、protected的static成员虽然可以在类外初始化,但是不能在类外被访问。
static成员函数特点:
静态成员函数是类的内部实现,属于类定义的一部分。普通成员函数一般隐含this指针,指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象,所以this是默认的。而静态成员函数由于不是与任何对象相联系,因此不具有this指针。从这个意义讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,只能调用静态数据成员和静态成员函数。
在C++中,类的静态成员(static member)必须在类内声明,在类外初始化,为什么?因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。
《c++primer》里面说在类外定义和初始化是保证static成员变量只被定义一次的好方法。但为什么static const int就可以在类里面初始化呢?
想起C中一个函数里定义一个static变量是为了保证只初始化一次。那么,是否可以这样理解:static数据成员在类外定义和初始化是为了保证只被定义和初始化一次,这样编译器就不必考虑类的函数里面第一个对static变量的’=’操作是赋值还是初始化了。static const int可以在类里面初始化,是因为它既然是const的,那程序就不会再去试图初始化了,碰到初始化语句就跳过?
class A
{
private:
staticint count ;//类内声明
};
int A::count = 0 ; //类外初始化(不是赋值,注意格式),不必再加static关键字
class B
{
private:
static int count = 0; //静态成员不能在类内初始化,不能保证只初始化一次,会导致每个对象都包含该静态成员
};
class C
{
private:
const int count = 0; //常量成员不能在类中声明的地方初始化,因为此时类并没有进行实例化(创建对象),因此并没有分配内存,只是一个样式,不能进行初始化。
};
class D
{
private:
static const int count = 0; //静态常量成员可以在类内初始化,第一个实例化对象时会初始化count,后来因为是const类型就不会再次初始化了,这条语句就不会再调用?
static const float count = 0.0; //errorC2864:只有静态常量整型数据成员才可以在类中初始化
};
结论:
静态常量数据成员可以在类内初始化(即类内声明的同时初始化),也可以在类外,即类的实现文件中初始化,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化;
静态非常量数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化;
非静态的常量数据成员不能在类内初始化,也不能在构造函数中初始化,而只能且必须在构造函数的初始化列表中初始化;
非静态的非常量数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表中初始化;
总结如下表:
类型 初始化方式 | 类内(声明) | 类外(类实现文件) | 构造函数中 | 构造函数的初始化列表 |
非静态非常量数据成员 | N | N | Y | Y |
非静态常量数据成员 | N | N | N | Y (must) |
静态非常量数据成员 | N | Y (must) | N | N |
静态常量数据成员 | Y | Y | N | N |
以下三种类型必须通过初始化列表来初始化
1.非静态常量
2. 引用类型
3. 没有默认构造函数的类类型