类/结构的静态成员
静态成员
类成员可以使用存储类修饰符static进行声明。这些数据成员通过该类的所有实例共享并存储在一个地方。为每个类对象变量创建非静态数据成员。
无法声明类的静态成员会导致需要在程序的全局层面声明这些数据。它会破坏数据及其类之间的关系,且不符合OOP的基本范式-加入数据和在类中处理它们的方法。静态成员允许类数据不特定于具体实例,存在于类的范围。
由于静态类成员不依赖于具体实例,则对它的引用如下:
这里 class_name 是类的名称,而 variable 是类成员的名称。
如您所见,如果访问类的静态成员,则会使用内容解析运算符 :: 。 当您在类方法访问静态成员,内容操作符为可选项。
类的静态成员必须以所需的值进行显式初始化。为此,它必须在全局范围声明和初始化。静态成员初始化的顺序对应其在全局范围声明的顺序。
例如,我们有一个用于解析文本的CParser 类,并且我们需要统计处理单词和字符的总数。我们只需将必要的类成员声明为静态并在全局层面给予初始化。然后类的所有实例都将使用常见的单词和字符计数器。
//+------------------------------------------------------------------+
//| 类 "文本解析" |
//+------------------------------------------------------------------+
class CParser
{
public:
static int s_words;
static int s_symbols;
//--- 构造函数和析构函数
CParser(void);
~CParser(void){};
};
...
//--- 全局层面解析类静态成员的初始化
int CParser::s_words=0;
int CParser::s_symbols=0;
|
静态类成员可以通过 const关键字来声明。这种静态常量必须在全局层面以const 关键字进行初始化:
//+------------------------------------------------------------------+
//| 类 "Stack" 存储处理数据 |
//+------------------------------------------------------------------+
class CStack
{
public:
CStack(void);
~CStack(void){};
...
private:
static const int s_max_length; // 最大存储栈能力
};
//--- 初始化CStack类的静态常量
const int CStack::s_max_length=1000;
|
指针 this #
关键字 this 表示一个隐式声明的其本身的指针 到类的特定实例,执行方法的快捷菜单。它只可以使用在非静态类方法。指针 this 是任何类的隐式非静态成员。
在静态函数中您只可以访问静态成员/类方法。
静态方法
在MQL5可以使用静态 类型成员函数。在类内部的声明,静态 修饰符必须在函数返回类型之前。
class CStack
{
public:
//--- 构造函数和析构函数
CStack(void){};
~CStack(void){};
//--- 最大堆栈能力
static int Capacity();
private:
int m_length; // 存储栈中的元素数量
static const int s_max_length; // 最大存储栈能力
};
//+------------------------------------------------------------------+
//| 返回堆栈中存储的元素的最大数量 |
//+------------------------------------------------------------------+
int CStack::Capacity(void)
{
return(s_max_length);
}
//--- 初始化CStack 类的静态常量
const int CStack::s_max_length=1000;
//+------------------------------------------------------------------+
//| 脚本程序起始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 声明 CStack 类型变量
CStack stack;
//--- 调用对象的静态方法
Print("CStack.s_max_length=",stack.Capacity());
//--- 它也可以按以下方式调用,因为方法是静态的,无需对象的存在
Print("CStack.s_max_length=",CStack::Capacity());
}
|
const 修饰符方法被称为常量并且不能修改类的隐式成员。声明类的常量函数和常量参数被称为const-correctness控制。通过这个控制,可以保证,编译器将确保对象值的一致性并且如果有什么问题,在编译过程中将会返回一个错误。
参数列表进入类声明以后才会放置const 修饰符。类以外的定义也应该包括 const 修饰符:
//+------------------------------------------------------------------+
//| “矩形”类 |
//+------------------------------------------------------------------+
class CRectangle
{
private:
double m_width; // 宽度
double m_height; // 高度
public:
//--- 构造函数和析构函数
CRectangle(void):m_width(0),m_height(0){};
CRectangle(const double w,const double h):m_width(w),m_height(h){};
~CRectangle(void){};
//--- 计算区域
double Square(void) const;
static double Square(const double w,const double h);// { return(w*h); }
};
//+------------------------------------------------------------------+
//| 返回“矩形”对象区域 |
//+------------------------------------------------------------------+
double CRectangle::Square(void) const
{
return(Square(m_width,m_height));
}
//+------------------------------------------------------------------+
//| 返回两变量的产品 |
//+------------------------------------------------------------------+
static double CRectangle::Square(const double w,const double h)
{
return(w*h);
}
//+------------------------------------------------------------------+
//| 脚本程序起始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 创建等于5和6的矩形
CRectangle rect(5,6);
//--- 用常量方法找出矩形区域
PrintFormat("rect.Square()=%.2f",rect.Square());
//--- 通过类CRectangle的静态方法找出产品数量
PrintFormat("CRectangle::Square(2.0,1.5)=%f",CRectangle::Square(2.0,1.5));
}
|
通过常量控制新增的参数实际就是在这种情况下,编译器生成一个特殊的优化,例如。 在只读存储器放置常量对象。
静态函数不能使用 const 修饰符定义,因为当调用该函数时,该修饰符能够确保实例成员的恒性。但是,如上所述,静态函数不能访问非静态类成员。
另见
静态变量,变量,参考。修饰符 & 和关键字 this