C#문법

[C#문법] Part13 생성자(Constructor)와 소멸자(Destructor)

BlackWolfDev 2024. 10. 9. 16:08

[ 개요 ]

인스턴스를 생성할 때 자동으로 호출되는 함수가 있다.

GameCharacter warrior = new GameCharacter();

앞선 클래스 파트에서 인스턴스를 생성할 때 이런 코드를 봤었을 것이다.

new 키워드 뒤에 오는 GameCharacter()가 바로 생성자이다.

이번에는 생성자가 무엇인지 알아보고 그와 한 쌍을 이루는 소멸자가 무엇인지 알아보도록 하겠다.


[ 생성자란 ]

인스턴스 생성 시 자동으로 호출되는 함수로서 인스턴스 초기화 메서드라고 불린다.

어떤 인스턴스든 꼭 가지고 있는 메서드이다.

 

생성자에는 두 가지 종류가 있다.

  1. 기본 생성자(default constructor)
  2. 직접 정의한 생성자

기본 생성자는 사용자가 직접 생성자를 정의하지 않아도 자동으로 만들어지며 아무런 작동을 하지 않는 생성자이다.

앞선 클래스 파트에서 생성자를 따로 구현한게 없어보였는데

GameCharacter warrior = new GameCharacter();

이렇게 사용할 수 있었던 것도 기본 생성자가 있었기 때문이다.

그럼 직접 정의하는 생성자에 대해서도 알아보자


[ 생성자 구현 방법 ]

두 가지 규칙을 지켜주면 된다.

  1. 생성자의 이름은 클래스의 이름과 동일해야 한다.
  2. 생성자는 반환값이 없어야 한다.
클래스명(){
        //초기화할 값 or 없어도 됨
}

일단 메서드 선언에서 반환형을 사용하지 않는다.

메서드 안에서 초기화를 해줘도 되지만 없어도 괜찮다(없으면 디폴드 생성자와 동일)

class GameCharacter
{
    public string Name; //이름


    public GameCharacter(){
        Name = "여행자"; //이름 초기화
    }


    //자신의 이름을 말하는 함수
    public void TalkMyName(){
        Console.WriteLine("내 이름은 "+Name);
    }
}

만약 클래스명이 GameCharacter라면 생성자의 이름도 GameCharacter가 된다.

생성자 안에서 멤버 변수 Name을 “여행자”라는 값으로 초기화하였다.

클래스명(자료형 변수명){
	멤버변수 = 변수명 
}

위와 같이 입력값을 받아서 초기화 시켜줄 수 있다.

class GameCharacter
{
    public string Name; //이름


    public GameCharacter(string name){
        Name = name;
    }


    //자신의 이름을 말하는 함수
    public void TalkMyName(){
        Console.WriteLine("내 이름은 "+Name);
    }
}

생성자에 string name이라는 인자를 받아서 멤버 변수 Name에 초기화 시켜준 것을 볼 수 있다.

꼭 생성자 안에 멤버 변수를 초기화하라는 법은 없고 다양하게 사용할 수 있다.


[ 생성자 사용 방법 ]

클래스명 인스턴스명 = new 클래스명();

 

new 키워드를 사용하여 클래스명() 즉 생성자를 사용하면 된다.

클래스명 인스턴스명 = new 클래스명(인자);

만약 생성자가 인자를 받는다면 인자를 넣어줄 수 있다.

class ProgramClass
{
    public static void Main()
    {
       GameCharacter character = new GameCharacter();
       character.TalkMyName();
    }
}
class ProgramClass
{
    public static void Main()
    {
       GameCharacter character = new GameCharacter("여행자");
       character.TalkMyName();
    }
}

위의 두 가지 코드 예시처럼 생성자가 인자를 받지 않으면 생성자 안에 아무것도 안 넣고 호출하면 되고 인자를 받는다면 인자를 넣어 호출하면 된다.


[ 소멸자 ]

인스턴스가 메모리에서 해제될 때 자동으로 호출되는 메서드이다.

생성자와 반대라고 생각하면 이해하기 쉬울 것이다.

생성자에서 동적으로 할당된 메모리를 소멸자를 통해 해제한다고 생각하면 된다.

왜 소멸자를 사용해야 할까?

만약 동적으로 할당된 메모리를 해제하지 않는다면 메모리 누수가 발생할 수 있다.

클래스의 안전성과 효율성을 보장하기 위해 소멸자가 중요하다.


[ 소멸자 구현 방법 ]

두 가지 규칙을 지켜주면 된다.

  1. 소멸자의 이름은 클래스의 이름과 동일해야 하고 앞에 ‘~’을 붙여야 한다.
  2. 소멸자는 반환값이 없어야 한다.
  3. 소멸자는 클래스 별로 하나의 소멸자만을 가진다.
~클래스명(){
        //메모리 해제하는 코드
}
~GameCharacter(){
        //메모리 해제하는 코드
 }

[ 소멸자 사용 방법 ]

소멸자의 사용은 특별히 없다.

인스턴스가 소멸하면 자동으로 호출이 된다.

using System;


class GameCharacter
{
    public string[] ItemBox = new string[2]; // 세미콜론 추가


    public GameCharacter(string item1, string item2)
    {
        ItemBox[0] = item1;
        ItemBox[1] = item2;
        Console.WriteLine("생성자 호출");
    }

    ~GameCharacter()
    {
        Array.Clear(ItemBox);
        Console.WriteLine("소멸자 호출");
    }
}


class ProgramClass
{
    public static void Main()
    {
        GameCharacter character = new GameCharacter("한손무기", "방패");
        return;
    }
}

위와 같은 코드가 있다고 하자

인스턴스를 생성하면 생성자를 호출한다.

그리고 Main 메서드가 종료되면 인스턴스가 사라지면서 소멸자를 호출할 것이다.

그러나 결과를 보면 “생성자 호출” 밖에 나오지 않는다.

아마 C,C++과 같은 언어로 구현했다면 “소멸자 호출”이라는 결과도 호출되었을 것이다.

 

그러나 .Net5 이상의 C#은 소멸자를 실행시키지 않는데 이유는 가비지 컬렉터(Garbage Collector)가 알아서 해결해 주기 때문이다.

나중에 깊게 다뤄볼 생각인데 간단히 말하자면 사용하지 않는 객체의 메모리를 GC(Garbage Collector)가 주기적으로 검사해서 청소해 준다.

자동으로 청소하는 건 좋은데 그 실행 시점이 GC가 판단해서 처리하니까 우리가 원하는 메모리 해제 지점을 예측하기가 어렵다.

using System;


class GameCharacter
{
    public string[] ItemBox = new string[2]; // 세미콜론 추가


    public GameCharacter(string item1, string item2)
    {
        ItemBox[0] = item1;
        ItemBox[1] = item2;
        Console.WriteLine("생성자 호출");
    }


    ~GameCharacter()
    {
        Array.Clear(ItemBox);
        Console.WriteLine("소멸자 호출");
    }
}
class ProgramClass
{
    public static void Main()
    {
        Temp();
        GC.Collect();
    }
    public static void Temp(){
        GameCharacter character = new GameCharacter("한손무기", "방패");
    }
}

그래서 위의 코드는 GC를 강제로 수집하도록 구현하였다.

Temp()를 통해 character 인스턴스를 지역변수처럼 생성과 해제하게 만들고

GC.Collect()를 이용하여 강제 수집하도록 명령하였다.

GC가 호출되면서 메모리에 할당된 것을 수거해가며 소멸자를 호출한 것을 알 수 있다.





 

728x90
반응형