注:一下来自侯捷著《深入浅出mfc 第二版》
静态成员(变量与函数)
我想你已经很清楚了,如果你依据一个类产生出三个对象,每一个对象将各有一份成员变量。有时候这并不是你要的。假设你有一个类,专门用来处理存款账户,它至少应该要有存户的姓名、地址、存款额、利率等成员变量:
class SavingAccount
{
private:
char m_name[40]; // 存户姓名
char m_addr[60]; // 存户地址
double m_total; // 存款额
double m_rate; // 利率
...
};
这家行库采用浮动利率,每个账户的利息都是根据当天的挂牌利率来计算。这时候m_rate 就不适合成为每个账户对象中的一笔数据,否则每天一开市,光把所有账户内容叫出来,修改 m_rate 的值,就花掉不少时间。m_rate 应该独立在各对象之外,成为类独一无二的数据。怎么做?在 m_rate 前面加上 static 修饰词即可:
class SavingAccount
{
private:
char m_name[40]; // 存户姓名
char m_addr[60]; // 存户地址
double m_total; // 存款额
static double m_rate; // 利率
...
};
static 成员变量不属于对象的一部分,而是类的一部分,所以程序可以在还没有诞生任何对象的时候就处理此种成员变量。但首先你必须初始化它。
不要把 static 成员变量的初始化动作安排在类的构造函数中,因为构造函数可能一再被调用,而变量的初值却只应该设定一次。也不要把初始化动作安排在头文件中,因为它可能会被含入许多地方,因此也就可能被执行许多次。你应该在实现文件中且类以外的任何位置设定其初值。例如在 main 之中,或全局函数中,或任何函数之外:
double SavingAccount::m_rate = 0.0075; // 设立 static 成员变量的初值
void main() { ... }
这么做可曾考虑到 m_rate 是个 private 数据?没关系,设定 static 成员变量初值时,不受任何存取权限的束缚。请注意,static 成员变量的类型也出现在初值设定句中,因为这是一个初值设定动作,不是一个数量指定(assignment)动作。事实上,static 成员变量是在这时候(而不是在类声明中)才定义出来的。如果你没有做这个初始化动作,会产生链接错误:
error LNK2001: unresolved external symbol "private: static double
SavingAccount::m_rate"(?m_rate@SavingAccount@@2HA)
下面是存取static成员变量的一种方式,注意,此刻还没有诞生任何对象实体:
// 第一种存取方式
void main()
{
SavingAccount::m_rate = 0.0075; // 欲此行成立,须把 m_rate 改为 public
}
下面这种情况则是产生一个对象后,通过对象来处理static成员变量:
// 第二种存取方式
void main()
{
SavingAccount myAccount;
myAccount.m_rate = 0.0075; // 欲此行成立,须把 m_rate 改为 public
}
你得搞清楚一个观念,static 成员变量并不是因为对象的实现而才得以实现,它本来就存在,你可以想象它是一个全局变量。因此,第一种处理方式在意义上比较不会给人错误的印象。
只要access level允许,任何函数(包括全局函数或成员函数,static 或 non-static)都可以存取static成员变量。但如果你希望在产生任何object之前就存取其class的private static 成员变量,则必须设计一个static成员函数(例如以下的 setRate):
class SavingAccount
{
private:
char m_name[40]; // 存户姓名
char m_addr[60]; // 存户地址
double m_total; // 存款额
static double m_rate; // 利率
...
public:
static void setRate(double newRate) { m_rate = newRate; }
...
};
double SavingAccount::m_rate = 0.0075; // 设立 static 成员变量的初值
void main()
{
SavingAccount::setRate(0.0074); // 直接调用类的 static 成员函数
SavingAccount myAccount;
myAccount.setRate(0.0074); // 通过对象调用 static 成员函数
}
由于static成员函数不需要借助任何对象,就可以被调用执行,所以编译器不会为它暗加一个this指针。也因为如此,static成员函数无法处理类之中的 non-static 成员变量。还记得吗,我在前面说过,成员函数之所以能够以单一一份函数代码处理各个对象的数据而不紊乱,完全靠的是this指针的指示。
static 成员函数「没有this 参数」的这种性质,正是我们的MFC应用程序在准备callback函数时所需要的。第6章的 Hello World 例中我就会举这样一个实例。
获取更多帮主请关注小程序