类/结构的静态成员

静态成员

类成员可以使用存储类修饰符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(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