C++开发初级
995 浏览 5 years, 10 months
5.1 静态数据成员
版权声明: 转载请注明出处 http://www.codingsoho.com/静态数据成员
有时没必要让所有类对象都包含某个变量的副本,或者这么做无法完成特定的任务。数据成员可能只对类有意义,而不适用于拥有其副本的每个对象。
例如,您或许想给每个电子表格一个唯一的数字m,您需要一个从0开始的计数器,每个对象都可以从这个计数器得到自身的ID。
电子表格的计数器确实属于Spreadsheet类,但没必要使每个Spreadsheet对象都包含这个计数器的副本,因为您必须让所有的计数器都保持同步。
C++用静态(static)数据成员解决了这个问题。静态数据成员是属于类而不是对象的数据成员,您可将静态数据成员当作属于类的全局变量。
下面是spreadsheet类的定义,其中包含了新的数据成员静态计数器:
class Spreadsheet
{
protected:
static int sCounter = 0;
//static int sCounter; // Pre C++11
};
代码取自 SpreadsheetDataMembers\Spreadsheet.h
在C++11中,这就是您要做的全部工作。 如果您使用的C++版本早于C++11,那么稍微有一点麻烦。那样的话将无法在类定义中初始化静态成员,您不仅要在类定义中列出static类成员,还需要在源文件中为其分配内存,通常是定义类方法的那个源文件。
在此您还可以初始化静态成员,但注意与普通的变量以及数据成员不同,在默认情况下它们会被初始化为0。static指针会被初始化为nullptr。
下面的代码是C++11之前的编译器为sCounter分配空间并初始化的代码:
int Spreadsheet::sCounter = 0;
代码取自 SpreadsheetDataMembers\Spreadsheet.cpp
这行代码在函数或者方法外部,与声明全局变量非常类似,只是使用了作用域解析Spreadsheet::指出这是Spreadsheet类的一部分。
在类方法内访问静态数据成员
在类方法内部可以像使用普通数据成员那样使用静态数据成员。例如,您或许想要为Spreadsheet类创建一个mId成员,并在Spreadsheet构造函数中用sCounter成员初始化它。下面是包含了mId成员的Spreadsheet类定义:
class Spreadsheet
{
public:
int getId() const;
protected:
int mId;
static int sCounter = 0;
//static int sCounter; // Pre C++11
};
代码取自 SpreadsheetDataMembers\Spreadsheet.h
下面是Spreadsheet构造函数的实现,在此赋予初始ID值:
Spreadsheet::Spreadsheet(int inWidth, int inHeight)
: mWidth(inWidth),mHeight(inHeight)
{
mId = sCounter++;
mCells = new SpreadsheetCell* [mWidth];
for (int i = 0; i < mWidth; i++) {
mCells[i] = new SpreadsheetCell[mHeight];
}
}
代码取自 SpreadsheetDataMembers\Spreadsheet.cpp
您己经看到,构造函数可以访问sCounter,就好像这是一个普通成员。
下面是对ID赋值的复制构造函数:
Spreadsheet::Spreadsheet(const Spreadsheet& src)
{
mId = sCounter++;
copyFrom(src);
}
代码取自 SpreadsheetDataMembers\Spreadsheet.cpp
在赋值运算符中不应该复制ID。一旦给ID指定了某个对象,就不应该再改变。
在方法外访问静态数据成员
访问控制限定符适用于静态数据成员:sCounter是protected,因此不能在类方法之外访问。如果scounter是公有的,就可以在类方法外访问,具体方法是用::作用域解析运算符指出这个变量是Spreadsheet类的一部分:
int c=Spreadsheet::sCounter;
然而,建议您不要使用公有数据成员。您应该提供公有get/set()方法来授予访问权限。如果想要访问静态的数据成员,应该实现静态的get/set方法,这些内容将在本章后面介绍。