1 静态数据成员
要定义静态数据成员,只要在数据成员的定义前增加static关键字。静态数据成员不同于非静态的数据成员,一个类的静态数据成员仅创建和初始化一次,且在程序开始执行的时候创建,然后被该类的所有对象共享;而非静态的数据成员则随着对象的创建而多次创建和初始化。下面是静态数据成员定义的例:
例10-18 | |
class Test { public: static int public_int; private: static int private_int; }; void main() { Test::public_int = 145; // 正确 Test::private_int = 12; // 错误,不能访问私有的数据成员 } |
|
从上例我们可以看到:静态数据成员的访问方式是:类名::静态数据成员名但是,不能直接访问私有的数据成员。其实,上面的程序段只是为了介绍如何访问静态数据成员,不能通过编译器的的编译和连接。
一、私有的静态数据成员
为了说明私有的静态数据成员的使用,考虑下面的程序段:
class Directory
{
public: ...
private:
// 数据成员
static char path[];
};
数据成员path[]是一个私有的静态变量,在程序执行过程中,仅一个Directory::path[]存在,即使有多个Directory类的对象。静态的数据成员能够被类的成员函数访问,但不能在构造函数中初始化。这是因为静态数据成员在构造函数被调用之前就已经存在了。静态数据成员可以在定义时初始化,且必须在类和所有的成员函数之外,与全局变量初始化的方法一样。例如,类Directory的数据成员的定义与初始化方法如下:
// 静态数据成员的定义与初始化
char Directory::path [200] = "/usr/local";
// 无参的构造函数
Directory::Directory()
{ ... }
在类中的静态数据成员的定义,只是说明该类有这么一个数据成员,并没有为该数据成员分配内存。就象非静态数据成员是在创建对象时分配内存一样,静态数据成员是在初始化时分配内存的。所以,在定义静态的数组成员时,可以省略它的尺寸(数组元素的个数),但在初始化时,必须确定数组的尺寸。
二、公有的静态数据成员
数据成员也可以是公有的,不过我们很少定义公有的数据成员,因为它破坏了数据隐藏的原则。如果Directory类的成员path[]定义为公有的,则该成员可在类外的任一地方访问:
void main()
{
strcpy(Directory::path, "/usr/local/pub"); //修改path的值
…
}
path仍然必须先初始化:
char Directory::path[200];
为什么需要静态数据成员?
类的静态数据成员拥有一块单独的存储区,而不管我们创建了多少个该类的对象。也就是说,静态数据成员被类的所有对象共享,它是属于类,而不是属于对象的。所有对象的静态数据成员都共享一块静态存储空间,可以节省内存,也为对象之间提供了一种互相通信的方法。静态数据成员的作用域在类内,也有public(公有)、private(私有)或者protected(保护)三种访问权限。 静态数据成员的存储空间分配 对于非静态数据成员而言,有多少个对象,就有多少个不同的内存单元,它们分布在各个对象的存储空间中。静态数据成员不同于非静态数据成员,不管有多少个对象,它们都共享相同的内存单元。所以,静态数据成员不应该属于任何一个对象,说它属于类更确切。
我们用一个例子来说明这种存储空间的关系, 对于类:
class C
{
static int si;
static int sc;
int i;
char c;
……
};
如果我们创建了类C的三个对象c1、c2和c3,那么它们的数据成员的存储关系如图10-2所示:
图10-2 | |
静态数据成员的初始化必须在类外,例如:
class A
{
public:
static int i; //……
};
静态数据成员i的初始化方法为:
int A::i=1;
可见:它与全局变量的初始化的方法的不同之处在于,有类名和作用域分隔符指定i的范围。
我们还可以定义静态的数组成员,例如:
例10-19 | |
class Values { private: static const int size; static const float table[4]; static char letters[5]; }; const int Values::size = 100; const float Values::table[4] = {1.1, 2.2, 3.3, 4.4}; char Values::letters[5] = {'a', 'b', 'c', 'd', 'e'}; void main(){} |
|
成员常量
我们先看下面一个实例:
class A
{
const size = 100; //illegal
int array[size]; //illegal
};
类A是想定义一个常量数组,但这个类的定义是错误的。因为定义类常量数据成员时,不能同时进行初始化。定义类时,只是说明类有那些数据成员,而不涉及到内存单元的分配,类数据成员存储单元的分配是在对象初始化时进行的。 我们也可以把常量数据成员定义成静态的,同静态成员变量初始化一样,静态成员常量初始化也在类外,
例如:
例10-20 | |
class A { static const int size; int array[size]; public: // ... }; const int A::size = 100; //definition
|
嵌套类和局部类中静态成员变量的使用 可以很容易地把一个静态数据成员放在一个嵌套类中,它是非嵌套类中静态数据成员情况的扩展,只将它的范围进行另一个级别的指定就可以了。然而,在局部类(如在函数内部定义的类)中不能有静态数据成员。例如:
|