[C#] 16. this와 base의 키워드


Study/C#  2020. 7. 22. 19:05

안녕하세요. 명월입니다.


이 글은 C#에서의 this와 base의 키워드에 대한 글입니다.


예전에 제가 클래스의 인스턴스를 생성하는 방법에 대해 설명한 적이 있습니다.

링크 - [C#] 10. 인스턴스 생성(new)과 메모리 할당(Stack 메모리와 Heap 메모리) 그리고 null


클래스 안의 구성에는 변수와 함수가 있습니다. 여기서 만약 함수 안의 변수명과 클래스안의 변수명이 같은 경우라면 우리가 그 변수를 참조할 때 어떤 변수를 가르킬까요?

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // data라는 변수
    private int data = 10;
    // data라는 변수 명을 가진 파라미터
    public void Print(int data)
    {
      // 콘솔 출력 - data의 출력은 현 stack에서 가장 가까운 파라미터 data를 가르킨다.
      Console.WriteLine("data - " + data);
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // Example 클래스 인스턴스 생성
      Example ex = new Example();
      // 함수 호출 - 파라미터로 20을 넣는다.
      ex.Print(20);

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위 예제를 보면 Example 클래스의 Print함수에는 파라미터 명을 data로 받고 클래스의 맴버 변수에도 data가 있습니다.

이럴 경우 data를 호출하면 Stack 내부의 data를 참조하게 됩니다.


그렇다면 내부에서 같은 변수 명을 사용할 경우 맴버 변수를 사용할 수 없는 것일까?

그래서 있는 것이 this입니다.


인스턴스 안에서 this의 의미는 자기 자신의 인스턴스를 가르키는 것입니다. 즉, this.data를 하게 되면 Example의 인스턴스의 data를 참조하는 것이기 때문에 파라미터의 변수가 아닌 맴버 변수를 참조하게 됩니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // data라는 변수
    private int data = 10;
    // data라는 변수 명을 가진 파라미터
    public void Print(int data)
    {
      // 콘솔 출력 (this.data 데이터는 인스턴스의 data이기 때문에 맴버 변수가 된다.)
      Console.WriteLine("data - " + this.data);
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // Example 클래스 인스턴스 생성
      Example ex = new Example();
      // 함수 호출 - 파라미터로 20을 넣는다.
      ex.Print(20);

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

이 this가 현재의 인스턴스를 가르키는 것에 대한 정확한 예제를 확인하겠습니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // 인스턴스의 주소 값을 리턴한다.
    public Example GetInstance()
    {
      // 자기 자신(인스턴스)를 리턴
      return this;
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // Example 클래스 인스턴스 생성
      Example ex = new Example();
      // ex의 GetInstance함수로 인스턴스를 받는다.
      Example ex1 = ex.GetInstance();

      // 두 변수의 해쉬 코드 값이 일치.. 즉, 같은 인스턴스를 의미한다.
      Console.WriteLine(ex.GetHashCode());
      Console.WriteLine(ex1.GetHashCode());

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위 예제에서 ex의 변수명으로 되어있는 인스턴스에서 GetInstance함수를 호출하여 this를 리턴받습니다.

this는 ex의 인스턴스를 가르키는 것으로 리턴받은 변수 ex1의 hashcode를 보면 ex와 같은 것을 확인할 수 있습니다.


그렇다면 this는 자기 자신의 인스턴스를 가르킵니다만, 상속을 받을 경우 부모 클래스를 참조하고 싶을 때가 있습니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // 맴버 변수
    private int data = 10;
    // 맴버 변수 data을 반환하는 함수
    public virtual int GetData()
    {
      // this는 Example 클래스의 맴버 변수
      return this.data;
    }
  }
  // Example를 상속한 SubExample 클래스
  class SubExample : Example
  {
    // 맴버 변수
    private int data = 20;
    // 맴버 변수 data을 반환하는 함수
    public override int GetData()
    {
      // this는 SubExample 클래스의 맴버 변수
      return this.data;
    }
    // 함수 호출
    public void Print()
    {
      // 콘솔 출력. this를 사용하였기 때문에 SubExample 클래스의 GetData 함수를 호출하여 SubExample클래스의 맴버 변수를 반환 받는다.
      Console.WriteLine("data - " + this.GetData());
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // Example 클래스 인스턴스 생성
      SubExample ex = new SubExample();
      // Print 함수 호출
      ex.Print();

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

SubExample에서 GetData함수를 재정의 했습니다. 그러나 사양에 따라서 상속한 부모 클래스의 GetData를 참조하고 싶을 때가 있습니다. 그럴 때는 base의 키워드로 찾아 갈 수 있습니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // 맴버 변수
    private int data = 10;
    // 맴버 변수 data을 반환하는 함수
    public virtual int GetData()
    {
      // this는 Example 클래스의 맴버 변수
      return this.data;
    }
  }
  // Example를 상속한 SubExample 클래스
  class SubExample : Example
  {
    // 맴버 변수
    private int data = 20;
    // 맴버 변수 data을 반환하는 함수
    public override int GetData()
    {
      // this는 SubExample 클래스의 맴버 변수
      return this.data;
    }
    // 함수 호출
    public void Print()
    {
      // 콘솔 출력. base를 사용하였기 때문에 부모 클래스의 GetData 함수를 호출하여 Example클래스의 맴버 변수를 반환 받는다.
      Console.WriteLine("data - " + base.GetData());
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // Example 클래스 인스턴스 생성
      SubExample ex = new SubExample();
      // Print 함수 호출
      ex.Print();

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위에서는 Print함수에서 base 키워드를 사용하였기 때문에 Example 클래스의 GetData 함수가 호출이 되었습니다.

Example 클래스의 GetData 함수에서 this를 사용하였지만 여기서는 SubExample가 아닌 Example의 맴버 변수를 참조하게 됩니다.

(※base는 this처럼 인스턴스 반환이 되지 않습니다. 즉, return base가 되지 않습니다.)


그리고 base는 부모 생성자를 호출할 수 있습니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // 생성자
    public Example(int data)
    {
      // 콘솔 출력
      Console.WriteLine("call Example constructor - " + data);
    }
  }
  // Example를 상속한 SubExample 클래스
  class SubExample : Example
  {
    // 생성자 (단, 생성자 파라미터가 없을 경우는 생략 가능하다.)
    public SubExample(int data) : base(10)
    {
      // 콘솔 출력
      Console.WriteLine("call SubExample constructor - " + data);
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // 인스턴스 생성
      SubExample ex = new SubExample(10);

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

여기서 생성자 옆에 상속받는 형태처럼 콜론(:)를 넣고 base를 넣어 부모 클래스의 생성자를 호출할 수 있습니다.

여기서 생성자에 파라미터가 없을 경우 이 base는 생략이 가능합니다.

using System;
namespace Example
{
  // 클래스 생성
  class Example
  {
    // 생성자
    public Example()
    {
      // 콘솔 출력
      Console.WriteLine("call Example constructor");
    }
  }
  // Example를 상속한 SubExample 클래스
  class SubExample : Example
  {
    // 생성자 (단, 생성자 파라미터가 없을 경우는 생략 가능하다.)
    public SubExample()
    {
      // 콘솔 출력
      Console.WriteLine("call SubExample constructor");
    }
  }
  class Program
  {
    // 실행 함수
    public static void Main(string[] args)
    {
      // 인스턴스 생성
      SubExample ex = new SubExample();

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위 예제는 base를 넣지 않아도 부모 생성자가 호출되는 것을 확인할 수 있습니다.


여기까지 C#에서의 this와 base의 키워드에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.