콘텐츠로 건너뛰기
Home » 생성자와 소멸자(Constructor and Destructor)

생성자와 소멸자(Constructor and Destructor)

  • by
생성자와 소멸자(Constructor and Destructor)

생성자(Constructor)

오늘은 생성자와 소멸자에 대해서 알아보도록 하겠습니다. 생성자와 소멸자를 간단히 소개하자면, 생성자는 객체를 생성할 때 호출되는 메소드이며, 소멸자는 객체를 소멸시킬 때 호출되는 메소드라고 할 수 있습니다. 우선 생성자 부터 알아보고, 이 생성자가 어떻게 쓰이는지 아래 예제를 살펴보며 생각해봅시다. 그러기 전, 생성자의 선언 형식부터 잠깐 보고 들어가보도록 합시다.

생성자의 선언 형식

class 클래스명 {
    한정자 클래스명(매개변수..) {
        //
    }
    ..
}

생성자의 선언 형식을 살펴보면, 생성자의 이름이 클래스의 이름과 똑같습니다. 그리고 이 생성자는 ‘매개변수’도 가질 수 있으며, 반환되는 값도 없고, 반환 타입도 없습니다. 그리고 한가지, 여기서 드러나지는 않았지만 생성자는 객체 생성시 호출되는 메소드이며, 우리가 따로 생성자를 구현해주지 않아도 컴파일러에서 생성자를 직접 만들어줍니다. 즉, 우리가 생성자를 만들지 않아도 자동으로 디폴트 생성자가 생성된다는 것입니다. 이제 한번 생성자를 직접 다뤄봅시다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Car
    {
        private int maxSpeed;
        private int speed = 0;
        private string model;

        public Car(int maxSpeed, string model)
        {
            this.maxSpeed = maxSpeed;
            this.model = model;
        }
        public void ShowCarInformation()
        {
            Console.WriteLine(model + "의 현재 속도: " + speed + "km/h, 최대 속도: " + maxSpeed + "km/h");
        }
        public void speedUp(int increment)
        {
            if (speed + increment > maxSpeed)
                Console.WriteLine("최대 속도 " + maxSpeed + "km/h를 넘길 수 없습니다.");
            else
            {
                speed += increment;
                Console.WriteLine(model + "의 현재 속도는 " + speed + "km/h 입니다.");
            }
        }
        public void speedDown(int decrement)
        {
            if (speed - decrement < 0)
                Console.WriteLine("속도는 0 아래로 떨어질 수 없습니다.");
            else
            {
                speed -= decrement;
                Console.WriteLine(model + "의 현재 속도는 " + speed + "km/h 입니다.");
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Car car = new Car(325, "람보르기니 가야르도");

            car.ShowCarInformation();
            car.speedUp(50);
            car.speedUp(40);
            car.speedUp(210);
            car.speedUp(30);
        }
    }
}
람보르기니 가야르도의 현재 속도: 0km/h, 최대 속도: 325km/h
람보르기니 가야르도의 현재 속도는 50km/h 입니다.
람보르기니 가야르도의 현재 속도는 90km/h 입니다.
람보르기니 가야르도의 현재 속도는 300km/h 입니다.
최대 속도 325km/h를 넘길 수 없습니다.
계속하려면 아무 키나 누르십시오 . . .

코드를 보시면서, 자세히 보셔야 할 부분은 15~19행 부분입니다. 이 부분에 생성자가 등장했으며, 매개변수로 정수형 값 하나와, 문자열 값 하나를 받는 부분이 있네요. 매개변수 maxSpeed의 값을 멤버 변수 maxSpeed에 넣고, 매개변수 model의 값을 멤버 변수 model에 넣습니다. 그리고 49행을 보시면 객체를 생성하면서 325란 값과, 람보르기니 가야르도라는 문자열 값이 넘어갔습니다. 즉, 객체를 생성할 때 생성자가 호출되면서 멤버 변수를 초기화 하고 있습니다. 객체를 생성하는 부분을 아래와 같이 볼 수도 있겠죠?

클래스명 객체명 = new 생성자;

(new 키워드로 인해 객체가 생성되고 자동으로 생성자가 호출된다.)

위 예제를 보시면, 생성자에는 일반적으로 객체를 생성하면서 멤버 변수를 자신이 원하는 값으로 초기화하는 부분이 들어갑니다. 한가지 더 알아두실게 있다면, 생성자도 오버로딩이 가능하다는 것입니다. 아래 예를 한번 보실까요?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("매개변수가 없는 디폴트 생성자");
        }
        public MyClass(int a)
        {
            Console.WriteLine("정수형 매개변수");
        }
        public MyClass(double d)
        {
            Console.WriteLine("실수형 매개변수");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass ma = new MyClass();
            MyClass mb = new MyClass(10);
            MyClass mc = new MyClass(25.5);
        }
    }
}
매개변수가 없는 디폴트 생성자
정수형 매개변수
실수형 매개변수
계속하려면 아무 키나 누르십시오 . . .

29~31행에서 ma, mb, mc라는 객체가 생성되면서 MyClass 생성자를 호출하죠? 넘어가는 매개변수 타입과 수에따라 이렇게 실행되는 영역을 바꿀 수 있습니다. 우리가 전에 배운 메소드 오버로딩 규칙이 그대로 적용된다고 보시면 됩니다. 이제는 소멸자에 대해서 알아보도록 할까요?

소멸자(Destructor)

소멸자는 생성자와 달리 가비지 컬렉터에 의해 객체가 소멸되는 시점을 판단하여 호출되는 메소드입니다. 여기서 가비지 컬렉터란, C#에서 효율적인 메모리 관리를 위해 가비지 컬렉터란 것이 자동으로 더이상 사용되지 않는 객체를 수거해갑니다. (가비지 컬렉터에 대해서는 나중에 자세히 다룰 예정입니다.) 소멸자는, 생성자와는 달리 상속되거나 오버로드 될 수도 없으며, 사용자가 호출할 수도 없습니다. 소멸자는 아래와 같은 형태로 쓰입니다. 

소멸자의 사용 형태

class 클래스명 {
   ~클래스명() {
      //
   }
   ..
}

위처럼 보시는 바와 같이, 클래스의 이름 앞에 ~ 기호를 붙인게 바로 소멸자입니다. 아래는 소멸자에 관한 예제입니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class MyClass
    {
        private string name;

        public MyClass(string name)
        {
            this.name = name;
            Console.WriteLine(name + "객체 생성!");
        }
        ~MyClass()
        {
            Console.WriteLine(name + "객체 소멸!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass ma = new MyClass("a");
            MyClass mb = new MyClass("b");
            MyClass mc = new MyClass("c");
        }
    }
}
a객체 생성!
b객체 생성!
c객체 생성!
c객체 소멸!
b객체 소멸!
a객체 소멸!
계속하려면 아무 키나 누르십시오 . . .

18행을 보시면 소멸자가 등장했음을 알 수 있습니다. 결과를 보시면 a, b, c 객체가 만들어진 뒤에 소멸하는 것을 확인할 수 있습니다. 그런데 소멸되는 순서를 보시면 a, b, c가 아닌 c, b, a 순으로 소멸되고 있죠? 이것은 가비지 컬렉터가 언제 움직일지, 어떤 순서로 소멸시킬지 모르기 때문에, 실행할때마다 소멸되는 순서는 바뀔 수 있습니다.

이런 소멸자는 가비지 컬렉터가 수거할 수 없는 자원이 있을 경우에 이를 해지할 때 사용합니다. 하지만 가급적, 소멸자를 사용하지 말라고 권하고 싶습니다. 객체의 소멸은 소멸자 없이도, 가비지 컬렉터가 처리할 수 있으며 소멸자가 굳이 필요하지 않은데도 불구하고 사용한다면 프로그램의 성능 저하만 유발할 수 있습니다.

댓글 남기기