类/结构的静态成员

静态成员

类成员可以使用存储类修饰符static进行声明。这些数据成员通过该类的所有实例共享并存储在一个地方。为每个类对象变量创建非静态数据成员。

无法声明类的静态成员会导致需要在程序的全局层面声明这些数据。它会破坏数据及其类之间的关系,且不符合OOP的基本范式-加入数据和在类中处理它们的方法。静态成员允许类数据不特定于具体实例,存在于类的范围。

由于静态类成员不依赖于具体实例,则对它的引用如下:

class_name::variable

这里 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(voidconst;
   static double     Square(const double w,const double h);// { return(w*h); }
  };
//+------------------------------------------------------------------+
//| 返回“矩形”对象区域                                                 |
//+------------------------------------------------------------------+
double CRectangle::Square(voidconst
  {
   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