상속

OOP의 특징은 상속을 통한 코드 재사용 장려입니다. 기존 클래스에서 새 클래스가 만들어지며 이를 기준 클래스라고 합니다. 파생 클래스는 기준 클래스의 멤버를 사용하지만 이러한 멤버를 수정 및 보완할 수도 있습니다.

많은 유형이 기존 유형의 변형입니다. 그들 각각에 맞는 새로운 코드를 개발하는 것은 종종 지루할 수 있습니다. 또한 새로운 코드는 새로운 오류를 암시합니다. 파생 클래스는 기준 클래스의 설명을 상속하므로 코드를 다시 개발하고 다시 테스트할 필요가 없습니다. 상속 관계는 계층적입니다.

계층은 모든 요소의 다양성과 복잡성을 복사할 수 있는 방법입니다. 이는 객체 분류를 소개합니다. 예를 들어, 원소들의 주기율표는 가스를 가지고 있습니다. 그들은 모든 주기적인 요소에 내재된 성질을 가지고 있다.

불활성 가스는 다음으로 중요한 하위 분류를 구성합니다. 위계질서는 아르곤과 같은 불활성 가스는 기체이고, 그 다음에 가스는 시스템의 일부입니다. 그러한 계층구조는 불활성 가스의 행동을 쉽게 해석할 수 있게 한다. 우리는 그들의 원자가 양자와 전자를 포함하고 있다는 것을 알고 있습니다. 그것은 다른 모든 원소들에 해당합니다.

우리는 그들이 실온에서 가스 상태에 있다는 것을 알고 있습니다. 모든 가스처럼요. 우리는 불활성 가스 하위 등급의 가스가 다른 원소와의 일반적인 화학 반응으로 들어가지 않는다는 것을 알고 있으며, 모든 불활성 가스의 특성입니다.

기하학적 도형의 상속 예를 고려해 보십시오. 단순 도형의 전체 다양성(원, 삼각형, 직사각형, 사각형 등)을 설명하려면 파생된 모든 클래스의 조상인 기준 클래스(ADT)를 만드는 것이 가장 좋습니다.

모양을 설명하는 가장 일반적인 멤버만 포함하는 기준 클래스 CShape를 만들겠습니다. 이러한 멤버는 쉐이프의 유형 및 주 고정점 좌표 등 모든 쉐이프의 특성을 설명합니다.

예제:

//--- 기준 클래스 쉐이프
class CShape
  {
protected:
   int       m_type;                   // 쉐이프 유형
   int       m_xpos;                   // X - 기준점 좌표
   int       m_ypos;                   // Y - 기준점 좌표
public:
             CShape(){m_type=0; m_xpos=0; m_ypos=0;} // constructor
   void      SetXPos(int x){m_xpos=x;} // set X
   void      SetYPos(int y){m_ypos=y;} // set Y
  };

다음으로 기준 클래스에서 파생된 새 클래스를 만듭니다. 여기서 각각 특정 클래스를 지정하는 필수 필드를 추가합니다. Circle 쉐이프의 경우 반지름 값을 포함하는 멤버를 추가해야 합니다. 사각형 쉐이프는 측면 값으로 설명됩니다. 따라서 기준 클래스 CShape에서 상속된 파생 클래스는 다음과 같이 선언됩니다:

//--- 파생 클래스 원
class CCircle : public CShape        // 콜론 뒤에 기준 클래스를 정의합니다
  {                                    // 상속할 수 있는
private:
   int             m_radius;           // 원 반지름
 
public:
                   CCircle(){m_type=1;}// 구성자, type 1 
  };

사각형 쉐이프 클래스 선언은 유사합니다:

//--- 파생 클래스 Square
class CSquare : public CShape        // 콜론 뒤에 기준 클래스를 정의합니다
  {                                    // 상속할 수 있는
private:
   int            m_square_side;       // 사각형 면
 
public:
                  CSquare(){m_type=2;} // 구성자, type 2 
  };

객체를 생성하는 동안 기준 클래스 생성자를 먼저 호출한 다음 파생 클래스의 구성자를 호출합니다. 개체가 먼저 제거되면 파생 클래스의 소멸자가 호출된 다음 기준 클래스 소멸자가 호출됩니다.

따라서 기준 클래스에서 가장 일반적인 멤버를 선언하여 특정 클래스를 지정하는 파생 클래스에 멤버를 추가할 수 있습니다. 상속을 통해 여러 번 재사용할 수 있는 강력한 코드 라이브러리를 만들 수 있습니다.

기존 클래스에서 파생 클래스를 만드는 구문은 다음과 같습니다:

class class_name : 
          (public | protected | privateopt  base_class_name
  {                                    
   클래스 멤버 선언
  };

 

파생된 부류의 한 측면은 멤버 계승자(상속인)의 가시성(개방성)입니다. 퍼블릭, 보호 및 프라이빗 키워드는 파생된 클래스에 사용할 수 있는 기준 클래스의 멤버를 나타내는 데 사용됩니다. 파생 클래스 머리글의 콜론 뒤에 있는 공용 키워드는 기준 클래스 CShape의 보호된 멤버와 공용 멤버를 파생 클래스 CCircle의 보호된 멤버와 공용 멤버로 상속해야 함을 나타냅니다.

파생 클래스에 대해 기준 클래스의 프라이빗 클래스 멤버를 사용할 수 없습니다. 공용 상속은 파생 클래스(CCircle 및 CSquare)가 CShapes임을 의미하기도 합니다. 즉, 정사각형(CSquare)은 도형(CSape)이지만 도형이 반드시 정사각형일 필요는 없습니다.

파생 클래스는 기준 클래스를 수정한 것으로, 기준 클래스의 보호된 멤버와 공용 멤버를 상속합니다. 기준 클래스의 생성자 및 소멸자를 상속할 수 없습니다. 기준 클래스 멤버 외에 파생 클래스에 새로운 멤버가 추가됩니다.

파생 클래스는 기준 클래스와 다른 멤버 함수의 구현을 포함할 수 있습니다. 동일한 함수 이름의 의미가 서명마다 다를 수 있는 경우 오버로드와 공통되는 것은 없습니다.

보호된 상속에서 기준 클래스의 공용 및 보호된 멤버는 파생 클래스의 보호된 멤버가 됩니다. 프라이빗 상속에서 기준 클래스의 공용 및 보호된 멤버는 파생 클래스의 프라이빗 멤버가 됩니다.

보호 및 비공개 상속에서 "파생형 클래스의 객체는 기준 클래스의 객체"라는 관계는 참이 아닙니다. 보호된 상속 유형 및 프라이빗 상속 유형은 드물며 각각 주의하여 사용해야 합니다.

상속 유형(공개, 보호 또는 비공개)은 파생 클래스에서 상속 계층의 기준 클래스 멤버에 액세스하는 방법에는 영향을 미치지 않습니다. 모든 유형의 상속에서 공개 및 보호된 액세스 지정자로 선언된 기준 클래스 멤버만 파생된 클래스에서 사용할 수 있습니다. 다음 예시에서 고려해봅시다:

#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| 몇가지 액세스 유형이 있는 클래스 예제                            |
//+------------------------------------------------------------------+
class CBaseClass
  {
private:             //--- 파생 클래스에서 프라이빗 멤버를 사용할 수 없습니다
   int               m_member;
protected:           //--- 보호된 메서드는 기준 클래스와 파생 클래스에서 사용할 수 있습니다
   int               Member(){return(m_member);}
public:              //--- 클래스 생성자는 모든 클래스 멤버가 사용할 수 있습니다
                     CBaseClass(){m_member=5;return;};
private:             //--- m_member에 값을 할당하는 비공개 방법
   void              Member(int value) { m_member=value;};
 
  };
//+------------------------------------------------------------------+
//| 오류가 있는 파생 클래스                                        |
//+------------------------------------------------------------------+
class CDerived: public CBaseClass // 기본값이므로 공용 상속의 지정을 생략할 수 있습니다
  {
public:
   void Func() // 파생 클래스에서 기준 클래스 멤버에 대한 호출을 포함하는 함수를 정의합니다
     {
      //--- 기준 클래스의 프라이빗 멤버 수정 시도
      m_member=0;        // 오류, 기준 클래스의 프라이빗 멤버를 사용할 수 없습니다
      Member(0);         // 오류, 기준 클래스의 전용 메서드를 파생 클래스에서 사용할 수 없습니다
      //--- 기준 클래스의 멤버 읽기
      Print(m_member);   // 오류, 기준 클래스의 프라이빗 멤버를 사용할 수 없습니다
      Print(Member());   // 오류 없음, 보호된 메서드를 기준 클래스와 해당 파생 클래스에서 사용할 수 있습니다
    }
  };

위의 예에서 CBaseClass는 공용 메서드인 생성자만 있습니다. 클래스 개체를 만들 때 생성자가 자동으로 호출됩니다. 따라서 프라이빗 멤버와 보호 메소드 Member()는 외부에서 호출할 수 없습니다. 그러나 공용 상속의 경우 파생 클래스에서 기준 클래스의 Member() 메서드를 사용할 수 있습니다.

보호된 상속의 경우 공용 및 보호된 액세스 권한이 있는 기준 클래스의 모든 멤버가 보호됩니다. 이는 공공데이터 멤버와 기준 클래스의 메서드가 외부로부터 접근할 수 있고, 보호상속은 파생 클래스와 그 파생에서만 이용할 수 있다는 것을 의미합니다.

//+------------------------------------------------------------------+
//| 몇가지 액세스 유형이 있는 클래스 예제                            |
//+------------------------------------------------------------------+
class CBaseMathClass
  {
private:             //--- 파생 클래스에서 프라이빗 멤버를 사용할 수 없습니다
   double            m_Pi;
public:              //--- m_Pi 값 가져오기 및 설정
   void              SetPI(double v){m_Pi=v;return;};
   double            GetPI(){return m_Pi;};
public:              // 클래스 생성자는 모든 멤버가 사용할 수 있습니다
                     CBaseMathClass() {SetPI(3.14);  PrintFormat("%s",__FUNCTION__);};
  };
//+------------------------------------------------------------------+
//| Derived class, in which m_Pi cannot be modified                  |
//+------------------------------------------------------------------+
class CProtectedChildClass: protected CBaseMathClass // 보호 상속
  {
private:
   double            m_radius;
public:              //--- 파생 클래스의 공용 메서드
   void              SetRadius(double r){m_radius=r; return;};
   double            GetCircleLength(){return GetPI()*m_radius;};
  };
//+------------------------------------------------------------------+
//| 스크립트 시작 함수                                         |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- 파생 클래스를 만들 때 기준 클래스의 생성자가 자동으로 호출됩니다
   CProtectedChildClass pt;
//--- 반지름 입력
   pt.SetRadius(10);
   PrintFormat("Length=%G",pt.GetCircleLength());
//--- 아래 라인에 대한 설명을 해제하면 SetPI()가 보호되므로 컴파일 단계에서 오류가 발생합니다
// pt.SetPI(3); 
 
//--- 이제 기준 클래스의 변수를 선언하고 Pi 상수를 10으로 설정해 보십시오
   CBaseMathClass bc;
   bc.SetPI(10);
//--- 여기 결과가 있습니다
   PrintFormat("bc.GetPI()=%G",bc.GetPI());
  }

이 예에서는 기준 클래스 CBaseMathClass의 SetPI() 및 GetPi() 메서드가 열려 있으며 프로그램의 모든 위치에서 호출할 수 있음을 보여 줍니다. 그러나 이와 동시에 CProtectedChildClass에서 파생된 이러한 메서드는 CProtectedChildClass 클래스 또는 해당 파생 클래스의 메서드에서만 호출할 수 있습니다.

프라이빗 상속의 경우 공인이 있는 기초계층 멤버 전원접근 보호가 되어 추가 상속 시 호출이 불가능해집니다.

MQL5에는 다중 상속이 없습니다.

더 보기

구조 및 클래스