본문 바로가기

C# 일기

4. 생성자 (Constructor)

이번에는 C#의 클래스에 있는 요소들 중, 생성자에 대해 다루어 보겠다.

 

우선, C# 클래스의 구조는 C++때와는 조금 다른데, C#클래스의 구조를 보자.

 

using System;

namespace Favor
{
   class Player
   {
      int hp;
   }
   internal class Program
   {
      static void Main(string[] args)
      {
         
      }
   }
}

 

간략하게 Player라는 class를 만들어보았다.

 

C++에서 다뤘던 때와 달리, 굉장히 간소해졌다.

 

public 멤버와 private 구역을 나누는 public: private:이 모두 없다.

 

대신, 이제 class에서 선언되는 멤버들은 따로 접근제한자(public, private...)를 설정하지 않으면 디폴트로 private로 설정된다.

 

즉 여기서 선언된 int hp는 외부에서는 접근이 불가능하고, Player 내부에서만 접근이 가능하다.

 

이 점을 제외하고는 C++의 클래스와 동일하게 멤버 함수와 멤버 변수를 선언 및 정의할 수 있으니 해당 부분은 넘어가도록 하겠다.

 

 

 

 

C++에서 클래스를 배울 때 잠깐 언급했던 생성자와 소멸자에 대해 알아보겠다.

 

생성자는 말 그대로 클래스를 생성할 때 호출되는 함수다.

 

생성이라는 말 보다는 인스턴스. 즉, 함수에 클래스의 요소들을 갖춘 객체에게 메모리 공간을 할당한다는 뜻을 사용하는 것이 더 바람직할 것 같다.

 

좌우지간 생성자는 클래스가 인스턴스될 때 호출되는 함수이다.

 

 

using System;

namespace Favor
{
   class Player
   {
      int hp;
   }
   internal class Program
   {
      static void Main(string[] args)
      {
         Player player = new Player();	// 생성자 호출
      }
   }
}

 

위의 코드를 보았을 때, new Player(); 가 실행되는 순간에 생성자가 호출되는 것이다.

 

그렇다면 이 생성자는 어떠한 역할을 하며, 어떻게 선언하고 사용해야할 지 알아보겠다.

 

먼저 생성자의 선언은 아래와 같다

 

 

using System;

namespace Favor
{
   class Player
   {
      int hp;
      public Player()
      {
            hp = 100;
      }
   }
   
   internal class Program
   {
      static void Main(string[] args)
      {
         Player player = new Player();
      }
   }
}

 

먼저 접근제한자를 사용한다. 이 때도 마찬가지로 따로 접근제한자를 지정하지 않으면 디폴트로 private으로 선언된다.

 

그 후, 클래스의 이름을 입력한다. 여기서는 Player클래스의 생성자를 만들어야 하므로 Player라고 입력했다.

 

그 다음 소괄호 안에 생성자의 매개변수를 입력한다. 생성자는 매개 변수를 받을 수도, 받지 않을 수도 있다.

 

그 후엔 클래스를 인스턴스했을 때 실행시킬 생성자의 기능을 안에 입력한다.

 

여기선, Player라는 클래스가 인스턴스 되면 체력을 100으로 설정하도록 입력했다.

 

이것이 생성자의 선언 방법이자, 생성자의 역할이다.

 

 

 

 

 

클래스가 인스턴스 됨과 동시에 실행되는 함수.

 

자세히 보면, 클래스를 선언할 때, new 뒤에 Player()라는 함수가 실행되는 것을 볼 수 있는데,

 

이 함수가 바로 생성자다.

 

즉 우리는 클래스를 인스턴스하는 코드를 직접 실행시킨 것이 아닌,

 

생성자를 통해 클래스를 생성하는 코드를 실행시킨 것이었다.

 

이렇듯 생성자의 선언은 함수의 선언과 닮아있다.

 

그러나 반환값을 명시하지않고, 함수의 이름이 없다는 점에서 명백히 구분할 수 있다.

 

 

 

또, 인스턴스시 실행해야 할 기능이 없는 클래스가 있기도 하다면, 생성자를 따로 선언하지 않아도 되는데,

 

이러한 경우에도 컴파일러는 아무런 내용도 기입되지 않은, 비어있는 생성자를 디폴트로 생성해준다.

 

 

 

 

 

앞서 클래스의 생성자는 매개변수를 받을 수도 있고, 받지 않아도 된다고 했는데, 이러한 특징을 갖고있기 때문에, 생성자도 오버로딩을 할 수 있다.

 

using System;

namespace Favor
{
   class Player
   {
      string name;
      int hp;
      public Player() { name = "플레이어"; hp = 100; }
      public Player(string s, int i) 
      {
         name = s;
         hp = i; 
      }
   }
   internal class Program
   {
      static void Main(string[] args)
      {
         Player player = new Player();
         Player warrior = new Player("전사", 200);
         
         // player : "플레이어", hp = 100
         // warrior : "전사", hp = 200
      }
   }
}

 

위와 같이 생성자 오버로딩을 통해 객체들마다 다른 특징을 지닌 채로, 혹은 다른 행동을 취하며 인스턴스 되도록 설정할 수 있다.

 

 

 

 

 

또한, C++에서 존재하던 소멸자 또한 C#에서도 구현할 수 있는데, 선언하는 방법은 아래와 같다.

 

using System;

namespace Favor
{
   class Player
   {
      ~Player() { Console.WriteLine("소멸자 호출");
   }
   
   internal class Program
   {
      static void Main(string[] args)
      {
         
      }
   }
}

 

C++에서의 소멸자는, 말 그대로 인스턴스 된 클래스가 할당 해제될 때, 쉽게 말해 사라질 때 호출되는 함수이다.

 

C++에서는 클래스를 선언하며 객체들이 서로 상호작용하는데에 필요한 자료들의 메모리 공간을 동적으로 할당하여 자료를 저장하고, 객체가 소멸할 때 동적 할당 했던 메모리를 다시 해제시켜줄 필요가 있어, 소멸자의 역할이 중요했다.

 

하지만 C#에서는 GC가 자동으로 할당 해제가 필요한 메모리들을 수집하여 할당 해제시켜주기 때문에, 소멸자의 기능이 다소 축소되었다.

 

정리하자면, C++에서는 생성자에서 동적할당한 메모리를 소멸자에서 해제시켜주지 않으면 메모리 누수로 인해 어려움을 겪을 수 있는데 반해, C#에서는 GC가 해당 기능을 수행하기 때문에 큰 문제를 겪지 않는다.

 

 

 

 

 

생성자의 개념을 알기 전에는 클래스가 인스턴스할 때 마다 취해야 할 행동들을 하나하나 다 입력했어야 했는데

 

생성자의 개념을 이해한 후로, 이러한 행동을 생성자 호출 한번으로 해결할 수 있게 되었으며,

 

생성자 오버로딩을 통해, 같은 클래스에서 동일한 객체를 생성하는 것이 아닌, 객체별로 다양한 특징과 행동을 설정할 수 있어 크게 도움이 되었다.

'C# 일기' 카테고리의 다른 글

6. 정적 멤버 (static)  (0) 2024.03.05
5. 얕은 복사(Shadow Copy)와 깊은 복사(Deep Copy)  (0) 2024.03.05
3. foreach문  (0) 2024.03.04
2. 배열  (0) 2024.03.04
1. 값 형식 변수와 참조 형식 변수  (0) 2024.03.04