본문 바로가기
C#

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

by RucA 2024. 4. 29.
728x90
반응형

클래스의 구성 요소 중 생성자와 소멸자(종료자)를 다룬다. 개체의 생성과 소멸에 관련된 메서드로, 생성자는 명시적으로 정의하고 호출해서 생성해야 하지만 소멸자는 필요하지 않다면 정의하지 않아도 닷넷 가비지컬렉터(Garbage Collector; GC)가 자동으로 역할을 해준다. 그렇게 어려운 개념은 아니므로 빠르게 다루고 넘어간다.

 

 

생성자(Constructor)


클래스 이름과 동일한 이름을 가지는 메서드로, 주로 클래스의 인스턴스를 생성할 때 사용된다. 클래스는 적어도 한 개의 생성자를 가진다. 생성자는 void를 포함한 반환값을 가지지 않음에 주의하자

 

  • 생성자를 사용한 개체 생성 : 클래스 이름과 동일한 이름으로 작성
using System;

class Hello
{
    //생성자 : 클래스 이름과 같다
    public Hello()
    {
        Console.WriteLine("Hello Constructor");
    }
    
    static void Main()
    {
        //생성자 호출
        Hello h = new Hello();
    }
}

 

  • 기본 생성자 : 매개 변수가 없는 생성자
    • 위의 예제는 매개 변수가 없는 기본 생성자이기도 하다.

 

  • 매개 변수가 있는 생성자
using System;

class User
{
    //User 클래스의 필드
    private string _Name;
    private int _Age;
    
    //생성자 : 매개 변수를 활용해 필드 값을 초기화
    public User(string name, int age)
    {
        this._Name = name;
        this._Age = age;
    }

    //메서드 : 필드 값 출력
    public void GetInfo()
    {
        Console.WriteLine($"name : {this._Name}, age : {this._Age}");
    }
    
    static void Main()
    {
        //생성자, 메서드 호출
        User Kim = new User("김밥", 25);
        Kim.GetInfo();
    }
}

 

  • 생성자 오버로드(overload) : 생성자 여러 개 만들기
using System;

class User
{
    //User 클래스의 필드
    private string _Name = "Unknown";
    private int _Age = -1;
    
    //기본 생성자
    public User()
    {
        this.GetInfo();
    }
    
    //생성자 오버로딩 : 값 1개 받기
    public User(string name)
    {
        this._Name = name;
        this.GetInfo();
    }
    
    //생성자 오버로딩 : 값 1개 받기
    public User(int age)
    {
        this._Age = age;
        this.GetInfo();
    }
    
    //생성자 오버로딩 : 값 2개 모두 받기
    public User(string name, int age)
    {
        this._Name = name;
        this._Age = age;
        this.GetInfo();
    }

    //메서드 : 필드 값 출력
    public void GetInfo()
    {
        Console.WriteLine($"name : {this._Name}, age : {this._Age}");
    }
    
    static void Main()
    {
        //다양한 생성자 호출
        User Lee = new User();
        User David = new User("David");
        User Lan = new User( 25);
        User Kim = new User("김밥", 25);
    }
}

 

생성자 오버로드 기능을 활용해 동일한 클래스로 유연한 초기화를 할 수 있다.

 

  • 정적 생성자와 인스턴스 생성자
    • 정적 생성자 (static 키워드) : 클래스의 정적 멤버를 호출할 때 가장 먼저 호출, 매개 변수 없음 
    • 인스턴스 생성자 (주로 public 키워드) : 일반적인 개체의 인스턴스를 생성
using System;

class User
{
    //User 클래스의 필드
    private static string _Name;
    private int _Age = 20;
    
    //정적 생성자
    static User()
    {
        _Name = "김정적";
    }

    //인스턴스 생성자
    public User( int age)
    {
        this._Age = age;
    }

    //정적 메서드 : 이름 값 출력
    public static void GetName()
    {
        Console.WriteLine($"name : {_Name}");
    }

    //인스턴스 메서드 : 나이 값 출력
    public void GetAge()
    {
        Console.WriteLine($"age : {this._Age}");
    }
    
    static void Main()
    {
        //정적 생성자(자동적으로 먼저 호출됨), 메서드 호출
        User.GetName();
        
        //인스턴스 생성자, 메서드 호출
        User Kim = new User(25);
        Kim.GetAge();
    }
}
//출력: name : 김정적  age : 25

 

  • this() 생성자를 활용한 생성자 포워딩(forwarding)
using System;

class User
{
    //User 클래스의 필드
    private string _Name;
    
    //기본 생성자
    public User()
    {
        this._Name = "김기본";
        this.GetName();
    }
    
    //this() 생성자를 활용한 생성자 포워딩 
    public User(string name) : this()
    {
        this._Name = name;
        this.GetName();
    }
    
    //메서드 : 이름 값 출력
    public void GetName()
    {
        Console.WriteLine($"name : {_Name}");
    }
    
    
    static void Main()
    {
        User Kim = new User("김포워딩");
    }
}
//출력 : name : 김기본  name : 김포워딩

 

this() 생성자를 활용해 생성자를 포워딩하는 것으로 다른 생성자에 값을 전달하기 용이하다. 위의 예제 같은 상황 말고도, 택시의 기본 요금을 모범 택시의 기본 요금으로 덮어 씌우는 상황 등에서 활용할 수 있을 것이다. 또한 상속에서 다루는 base()를 사용해 부모 클래스의 생성자에 값을 전달할 수 있다.(상속 관련 포스팅에서 다룰 예정)

 

  • 생성자를 활용한 읽기 전용 필드 초기화
    • readonly 키워드를 사용해 정의된 필드는 읽기 전용 필드로, 생성자로만 초기화 가능. 이후 변경 불가
using System;

class User
{
    //읽기 전용 필드
    private readonly string _Name;
    
    //생성자에서만 읽기 전용 필드를 초기화 가능
    public User(string name)
    {
        this._Name = name;
    } 
    
    //메서드 : 이름 값 출력
    public void GetName()
    {
        Console.WriteLine($"name : {_Name}");
    }
    
    static void Main()
    {
        User Kim = new User("김읽기전용");
        Kim.GetName();
    }
}

 

 

  • 식 본문 생성자(expression bodied constructor) : 람다식의 화살표 연산자를 사용해 생성자를 줄여 표현하는 것
using System;

class User
{
    //User 클래스의 필드
    private string _Name;
    
    //식 본문 생성자
    public User(string name) => this._Name = name;
    
    //메서드 : 이름 값 출력
    public void GetName()
    {
        Console.WriteLine($"name : {_Name}");
    }
    
    static void Main()
    {
        User Kim = new User("김식본문");
        Kim.GetName();
    }
}

 

 

 

소멸자(Destructor)


클래스 이름 앞에 ~를 붙여 만드는 메서드로, 종료자(finalizer)라고도 한다. 닷넷의 가비지컬렉터(GC)에서 클래스의 인스턴스를 다 사용한 후 정리할 때 실행되는 메서드로, 클래스에서 가장 마지막으로 호출되는 메서드이다. 소멸자는 매개변수를 받을 수 없으며, 오버로드를 지원하지 않고, 직접 호출할 수 없다. 정적 호출, 인스턴스 호출에 상관없이 형태 동일하다.

 

  • 소멸자 설정법 : ~클래스 이름()
using System;

class User
{
    //필드
    private string _Name;
    
    //생성자
    public User(string name) => this._Name = name;
    
    //메서드
    public void GetName()
    {
        Console.WriteLine($"name : {_Name}");
    }

    //소멸자
    ~User()
    {
        Console.WriteLine("유저 정보 폐기");
    }
    
    static void Main()
    {
        User Kim = new User("김소멸자");
        Kim.GetName();
        //GC.Collect()의 자동적 실행 : ~User() 호출됨
    }
}

 

C#에서는 GC가 존재해, 사용이 끝난 인스턴스를 자동적으로 제거해 메모리를 관리해준다. GC가 사용이 완료된 클래스 인스턴스를 제거할 때 소멸자를 호출한다. 일반적으로는 소멸자를 자주 쓰진 않는다.

728x90
반응형