250x250
Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

minjea.dev의 코딩블로그

[c#] 생성자와 소멸자, 그리고 this 본문

코딩강좌/c#

[c#] 생성자와 소멸자, 그리고 this

minjea.dev 2022. 4. 10. 12:00
728x90

이번시간에는 저번시간에 이어서, 생성자와 소멸자에 대하여 알아보도록 하겠습니다.

 

생성자

생성자란, 객체가 생성되는 시점에 호출되는 메서드라고 생각하시면 될듯 합니다. 즉, 인스턴스가 만들어지는 시점에 작동한다고 생각하시면 됩니다. 그렇다면 이 생성자는 어떻게 생성하고, 어떤 역할을 할까요?

 

일단 생성하는 법부터 알아보겠습니다. 생성하는 방법은 다음과 같습니다

class 클래스명 {
    [접근제한자] 클래스명(매개변수들) {
        code....
    }
}

위를 보시면 생성자의 이름이 클래스명과 동일하다는 점을 눈치채셨을 겁니다. 또한, 자세히 보면 반환타입도 없습니다. 그 이유는, 생성자는 메서드와는 달리 값을 반환할수 없기 때문입니다. 그 점을 제외하면 일반 메서드와 똑같다고 생각하시면 됩니다.

 

아래는 저번 시간에 만든 Human 클래스에 생성자를 추가한 예제입니다.

class Human {
    public string name;
    public int age;
    public string gender;
    
    public Human() {
        Console.WriteLine("Human 클래스의 생성자 동작!");
    }
    
    public void Eat() {
        Console.WriteLine(name+"(이)가 먹습니다");
    }
    
    public void Walk(int meter) {
        Console.WriteLine(name+"(이)가 "+meter+"미터를 걸었습니다.");
    }
}

이렇게 바뀐 클래스의 인스턴스를 생성하면....

Human woojin = new Human(); // 콘솔에 Human 클래스의 생성자 동작! 이 뜸

woojin이 생성되는 시점에, 콘솔에 메시지가 정상적으로 뜨는걸 보니, 잘 작동하는 것 같습니다. 이렇게 생성자에는 객체가 생성될 때, 작동해야 하는 코드를 넣어두면 됩니다. 그러면 객체가 생성될때, 그 코드가 자동으로 실행됩니다.

 

그런데, 저번 시간에는 생성자를 추가하지도 않았는데 왜 에러가 나지 않은 걸까요? 그 이유는 개발자가 따로 생성자를 정의하지 않았다면 C#이 자동으로 빈 생성자를 추가합니다. 다만, 아까처럼 따로 생성자를 명시한 경우에는 C#이 빈 생성자를 추가하지 않습니다.

 

또한, 생성자는 매개변수를 가질수도 있습니다. 일반적으로는 생성자는 내부 필드의 값을 설정하는 용도로 매개변수를 받습니다. 그렇다면, 저번처럼 woojin.name = "우진" 처럼 직접 값을 대입하는게 아니라, 생성자에 인자를 넘기는 방식으로 자동으로 값을 초기화할수 있을것 같습니다. 그럼 한번 시도해 봅시다. 다음과 같이 코드를 변경하고 객체를 생성했습니다.

class Human {
    public string name;
    public int age;
    public string gender;
    
    public Human(string name, int age, string gender) {
        name = name;
        age = age;
        gender = gender
    }
    
    public void Eat() {
        Console.WriteLine(name+"(이)가 먹습니다");
    }
    
    public void Walk(int meter) {
        Console.WriteLine(name+"(이)가 "+meter+"미터를 걸었습니다.");
    }
}

Human woojin = new Human("우진", 100, "Men");

그런데 에러가 발생합니다. 왜 그럴까요?

그 이유는, 매개변수의 이름이 필드의 이름과 동일하여 발생한 문제입니다. 즉, c# 컴파일러가, name, age, gender를 클래스 내부에서 가져와야 할지, 아니면 매개변수에서 가져와야할지 몰라서 에러를 발생시킨 것입니다. 그러면 이걸 어떻게 해결 할수 있을까요?

 

c#에서는 이럴때 쓰라고, this라는 자기자신을 가리키는 특별한 키워드를 제공합니다. this 뒤에 점을 찍고, 객체의 메서드나 필드의 이름을 쓰면 됩니다. 그러면 필드를 가져오거나, 메서드를 호출하는것이 가능합니다. 그러면, 다음과 같이 코드를 고칠수 있을 겁니다.

class Human {
    public string name;
    public int age;
    public string gender;
    
    public Human(string name, int age, string gender) {
        this.name = name;
        this.age = age;
        this.gender = gender
    }
    
    public void Eat() {
        Console.WriteLine(name+"(이)가 먹습니다");
    }
    
    public void Walk(int meter) {
        Console.WriteLine(name+"(이)가 "+meter+"미터를 걸었습니다.");
    }
}

Human woojin = new Human("우진", 100, "Men");

이렇게 하면 에러가 안 나고 잘 작동합니다. 그런데 Eat 메서드나 Walk 메서드에서는 this가 없어도 name에 잘 접근하고 있는데, 이건 어떻게 된 것일까요? 왜냐하면, Walk 메서드에는 매개변수에 name이라는 이름을 가진 매개변수가 존재하지 않기 때문에, this를 생략해도, c#에서 알아서 참조를 해 주었기 때문입니다.

 

그럼 다시 생성자로 돌아와서, 하나만 말씀드리고 종료자로 넘어가보도록 하겠습니다.

클래스마다 하나만 만들수 있을까요? 그건 아닙니다. 생성자를 여러개 정의할수도 있습니다. 다음과 같이 말이죠.

class Human {
    public string name;
    public int age;
    public string gender;
    
    public Human(string name) {
        this.name = name;
    }
    
    public Human(string name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public Human(string name, int age, string gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    public void Eat() {
        Console.WriteLine(name+"(이)가 먹습니다");
    }
    
    public void Walk(int meter) {
        Console.WriteLine(name+"(이)가 "+meter+"미터를 걸었습니다.");
    }
}

Human woojin = new Human("우진", 100, "Men");

저렇게 되면, 개발자는 여러개의 생성자중 마음에 드는걸 골라 사용할수 있습니다. 다음과 같이 말이죠.

Human vladimir = new Human("블라디미르");
Human sopia = new Human("소피아", 100);
Human woojin = new Human("우진", 100, "Men");

 

소멸자

c#에는 생성자의 반대인, 소멸자가 존재합니다. 소멸자는 말 그대로 객체가 소멸할때 작동합니다. 그러면 객체가 소멸하는 시점은 언제일까요?

 

객체는 참조형 변수이므로, 변수와 상수, 그리고 스택과 힙 강좌에서 말씀드린것처럼, 가비지 컬렉터라고 하는 특별한 기능을 가진 친구가 알아서 더이상 객체가 쓸모가 없어졌다고 판단되는 시점에 알아서 소멸시킵니다. 즉, 우리는 알수 없는 시점에 가비지 컬렉터에 의해 객체가 소멸된다는 소리인거죠.

 

그렇다면 소멸자는 어떻게 만들까요? 생성자와 동일합니다. 다만 이름 앞에 ~가 붙는다는 점을 제외한다면 말이죠. 다음은 Human 클래스에 소멸자를 추가한 예제입니다.

class Human {
    public string name;
    public int age;
    public string gender;
    
    public Human(string name) {
        this.name = name;
    }
    
    public Human(string name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public Human(string name, int age, string gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    public void Eat() {
        Console.WriteLine(name+"(이)가 먹습니다");
    }
    
    public void Walk(int meter) {
        Console.WriteLine(name+"(이)가 "+meter+"미터를 걸었습니다.");
    }
    
    public ~Human() {
        Console.WriteLine("Human 소멸자 작동!")
    }
}

Human woojin = new Human("우진", 100, "Men");

그렇지만 어차피 가비지 컬렉터가 알아서 객체를 소멸시키고, 메모리를 관리해주고 있으므로, 꼭 필요한 경우가 아니라면 가급적으로 소멸자는 사용하지 않는 것을 추천드립니다. 쓸데없이 소멸자를 정의해둔다면, 성능 부하가 발생할수 있기 때문입니다.

 

그렇다면 오늘은 여기까지 하고, 다음에는 정적 필드, 정적 메서드, 정적 생성자에 대해 알아보겠습니다

728x90

'코딩강좌 > c#' 카테고리의 다른 글

[c#] 접근제한자란?  (0) 2022.04.12
[c#] 정적 필드, 정적 메서드, 정적 생성자  (0) 2022.04.11
[c#] 클래스  (0) 2022.04.09
[c#] 반복문(break, continue, 그리고 goto문)  (1) 2022.04.08
[c#] 조건문  (0) 2022.04.07