静态成员
到目前为止,我们已经讨论了类的字段和方法,它们描述了给定类的对象的状态和行为。但在程序中,可能需要存储某些特性或对整个类(而不是其对象)执行操作。这种类属性称为静态,使用在类型前添加的 static 关键字进行描述。结构体和联合体也支持这样的类属性。
例如,我们可以在绘图程序中计算用户创建的形状数量。为此,我们将在 Shape 类中描述静态变量 count(Shapes5.mq5)。
class Shape
|
该变量在 private 部分中定义,因此无法从外部访问。
为读取当前计数器值,提供了一个公共静态方法 getCount()。理论上,由于静态成员是在类的上下文中定义的,因此它们的可见性会根据其所在部分的修饰符受到限制。
我们将在参数化构造函数 Shape 中将计数器加 1,并移除默认构造函数。因此,任何派生类型的形状的每个实例都将被考虑在内。
请注意,静态变量必须在类块之外显式定义(可以选择进行初始化):
static int Shape::count = 0; |
静态类变量类似于函数内的全局变量和静态变量(参见 静态变量部分),因为它们在程序启动时创建,并在程序卸载前被删除。因此,与对象变量不同,它们必须从一开始就作为单个实例存在。
在这种情况下,可以省略零初始化,因为众所周知,全局变量和静态变量默认设为零。数组也可以是静态的。
在静态变量的定义中,我们看到使用了特殊的上下文选择运算符 '::'。使用这个运算符,可以形成一个完全限定的变量名。'::' 左侧是变量所属类的名称,右侧是其标识符。显然,完全限定名很有必要,因为在不同的类中,可以声明具有相同标识符的静态变量,并且需要一种方法能够唯一引用每个变量。
相同的 '::' 运算符不仅用于访问公共静态类变量,还用于访问方法。具体来说,为了在 OnStart 函数中调用 getCount 方法,我们使用语法 Shape::getCount():
void OnStart()
|
由于现在正在生成指定数量的形状 (10),我们可以确认计数器正常运行。
如果您有一个类对象,您可以通过正常的取消引用来引用静态方法或属性(例如,shape.getCount()),但这样的符号可能会产生误导(因为它隐藏了该对象实际上未被访问这一事实)。
请注意,创建派生类不会以任何方式影响静态变量和方法:它们始终会被赋值给定义了它们的类。我们的计数器对于所有派生自 Shape 的形状的类都相同。
您不能在静态方法中使用 this,因为静态方法在执行时并不绑定到特定对象。此外,在静态方法中,如果不取消引用任何对象类型变量,则无法直接调用常规类方法或访问其字段。例如,如果您从 getCount 中调用 draw,则会遇到错误“访问非静态成员或函数”:
static int getCount()
|
出于同样的原因,静态方法不能为虚拟。
是否可以使用静态变量来计算形状的总数,而不是按类型计算其统计信息?是的,可以。此任务留待读者独立研究。感兴趣的读者可以在 Shapes5stats.mq5 脚本中找到一个实现示例。