클래스/구조의 정적 멤버

스태틱 멤버

스토리지 클래스 한정자 static을 사용하여 클래스의 멤버를 선언할 수 있습니다. 이러한 데이터 멤버는 이 클래스의 모든 인스턴스가 공유하며 한 곳에 저장됩니다. 각 클래스 개체 변수에 대해 정적이 아닌 데이터 멤버가 생성됩니다.

클래스의 정적 멤버를 선언할 수 없는 경우 이러한 데이터를 프로그램의 글로벌 수준에 선언해야 합니다. 데이터와 해당 클래스 간의 관계를 끊을 수 있으며, OOP의 기본 패러다임인 데이터와 클래스 내 데이터 처리 방법과 일치하지 않습니다. 정적 멤버를 사용하면 특정 인스턴스에 특정되지 않은 클래스 데이터가 클래스 범위에 존재할 수 있습니다.

정적 클래스 멤버는 특정 인스턴스에 종속되지 않으므로 이에 대한 참조는 다음과 같습니다:

class_name::variable

여기서 class_name는 클래스의 이름이고 variable은 클래스 멤버의 이름입니다.

보시다시피 클래스의 정적 멤버에 액세스하기 위해, context resolution 연산자 ::가 사용됩니다. 클래스 메서드 내에서 정적 멤버에 액세스할 때 컨텍스트 연산자는 선택 사항입니다.

클래스의 정적 멤버를 원하는 값으로 명시적으로 초기화해야 합니다. 이를 위해 전역 범위에서 선언 및 초기화해야 합니다. 정적 멤버 초기화 순서는 전역 범위에서 해당 선언의 순서에 해당합니다.

예를 들어, 텍스트 구문 분석 시 사용되는 클래스 CParser가 있으며, 처리된 총 단어와 문자 수를 세어야 합니다. 필요한 클래스 멤버를 정적 클래스 멤버로만 선언하고 글로벌 레벨에서 초기화하면 됩니다. 그러면 클래스의 모든 인스턴스가 단어와 문자의 공통 카운터를 사용합니다.

//+------------------------------------------------------------------+
//| 클래스 "Text analyzer"                                            |
//+------------------------------------------------------------------+
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는 메서드가 실행되는 클래스의 특정 인스턴스에 암시적으로 선언된 pointer를 나타냅니다. 클래스의 정적이 아닌 메서드에서만 사용할 수 있습니다. 포인터 this는 모든 클래스의 암시적 비정적 멤버입니다.

정적 함수에서는 클래스의 정적 멤버/메소드만 액세스할 수 있습니다.

정적 메서드

MQL5에서 static 유형의 멤버 함수를 사용할 수 있습니다. static 한정자는 클래스 내부의 선언에서 함수의 반환 유형 앞에 와야 합니다.

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 한정자도 포함되어야 합니다:

//+------------------------------------------------------------------+
//| 클래스 "Rectangle"                                                |
//+------------------------------------------------------------------+
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); }
  };
//+------------------------------------------------------------------+
//| "Rectangle" 객체의 영역을 반환합니다                       |
//+------------------------------------------------------------------+
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