게임에서 몬스터를 구현한다고 가정해 보겠습니다.
몬스터마다 이름과 체력이 필요하고, 공격받으면 체력이 감소하는 기능도 있어야 합니다.
이러한 데이터와 기능을 하나로 묶어 정의할 수 있도록 해주는 것이 클래스(Class)입니다.
클래스와 객체
클래스는 객체가 가질 속성과 기능을 정의하는 사용자 정의 형식입니다.
하나의 클래스를 바탕으로 여러 객체를 만들 수 있다는 점에서 설계도와 같은 역할을 한다고 볼 수 있습니다.
예를 들어 몬스터의 이름과 체력, 피해를 받는 기능을 Monster 클래스로 작성해 보겠습니다.
using System;
class Monster
{
public string Name;
public int HP;
public void TakeDamage(int damage)
{
HP -= damage;
}
}
class Program
{
static void Main()
{
Monster slime = new Monster();
Monster goblin = new Monster();
slime.Name = "슬라임";
slime.HP = 30;
goblin.Name = "고블린";
goblin.HP = 50;
slime.TakeDamage(10);
Console.WriteLine($"{slime.Name} HP : {slime.HP}");
Console.WriteLine($"{goblin.Name} HP : {goblin.HP}");
}
}
실행 결과
슬라임 HP : 20
고블린 HP : 50
Monster 클래스에는 이름과 체력을 저장하는 Name, HP 필드와 피해를 받는 TakeDamage() 메서드가 정의되어 있습니다.
필드는 객체의 상태를 저장하고, 메서드는 객체가 수행할 기능을 정의합니다. 이러한 필드와 메서드 등을 클래스의 멤버(Member)라고 부릅니다.
클래스는 어떤 속성과 기능을 가질지 정의한 것이며, 이를 바탕으로 실제 생성된 실체가 객체(Object)입니다.
C#에서는 new 연산자를 이용해 객체를 생성합니다.
Monster slime = new Monster();
Monster goblin = new Monster();
위 코드에서는 하나의 Monster 클래스를 바탕으로 슬라임과 고블린, 두 개의 객체를 생성했습니다.
각 객체는 독립적인 상태를 가지므로 슬라임이 피해를 받아 체력이 감소하더라도 고블린의 체력에는 영향을 주지 않습니다.

객체와 인스턴스의 차이
클래스를 공부하다 보면 객체뿐 아니라 인스턴스(Instance)라는 용어도 자주 등장합니다.
객체와 인스턴스는 완전히 다른 개념이라기보다 같은 실체를 어떤 관점에서 바라보는지에 따른 표현입니다.
| 구분 | 의미 |
| 클래스(Class) | 객체의 속성과 기능을 정의한 설계도 |
| 객체(Object) | 클래스를 바탕으로 실제 생성된 실체 |
| 인스턴스(Instance) | 특정 클래스로부터 생성되었다는 관계를 강조하는 표현 |
예를 들어 앞서 생성한 슬라임은 하나의 객체이면서 동시에 Monster 클래스의 인스턴스입니다.
즉, 인스턴스는 객체가 어떤 클래스로부터 생성되었는지를 강조할 때 사용하는 표현입니다.
참조 변수와 객체
C#에서 class로 정의한 형식은 참조 형식(Reference Type)입니다.
이는 클래스 형식의 변수가 객체의 데이터 자체를 저장하는 것이 아니라, 해당 객체에 접근하기 위한 참조를 저장한다는 의미입니다.
Monster slime = new Monster();
이 코드는 다음과 같이 나누어 작성할 수도 있습니다.
Monster slime;
slime = new Monster();
Monster slime;은 참조 변수를 선언한 것이고, new Monster()는 새로운 객체를 생성해 그 참조를 반환합니다.
따라서 변수를 선언하는 것과 객체를 생성하는 것은 서로 다른 과정입니다.
그렇다면 참조 변수를 다른 변수에 대입하면 어떻게 될까요?
Monster slime = new Monster();
slime.HP = 30;
Monster another = slime;
another.HP = 10;
Console.WriteLine(slime.HP);
실행 결과
10
another의 체력을 변경했는데도 slime의 체력이 함께 변경되었습니다. 왜 그럴까요?
Monster another = slime;
이 코드에서는 새로운 객체를 생성한 것이 아니라, slime에 저장된 참조를 another에 복사했기 때문입니다.
따라서 두 변수는 동일한 객체를 참조하며, 어느 변수를 통해 수정하더라도 같은 객체의 데이터가 변경됩니다.
반대로 new Monster()를 각각 실행했다면 서로 다른 객체가 생성되므로 한 객체의 데이터를 변경하더라도 다른 객체에는 영향을 주지 않습니다.

생성자(Constructor)
앞선 예제에서는 객체를 생성한 후 이름과 체력을 각각 할당했습니다.
Monster slime = new Monster();
slime.Name = "슬라임";
slime.HP = 30;
하지만 객체를 생성할 때마다 필요한 값을 직접 설정해야 한다면 초기화를 빠뜨릴 수도 있습니다.
이때 사용하는 것이 생성자(Constructor)입니다.
생성자는 객체가 생성되는 과정에서 호출되는 특별한 멤버로, 주로 객체의 초기 상태를 설정하는 역할을 합니다.
생성자는 클래스와 이름이 같으며, void를 포함한 반환 형식을 작성하지 않습니다.
앞서 작성한 Monster 클래스에 다음 생성자들을 추가해 보겠습니다.
public Monster()
{
Name = "이름 없음";
HP = 10;
}
public Monster(string name, int hp)
{
Name = name;
HP = hp;
}
이제 객체를 생성할 때 원하는 초기값을 전달하거나, 미리 지정한 기본값을 사용할 수 있습니다.
Monster monster1 = new Monster();
Monster monster2 = new Monster("슬라임", 30);
Console.WriteLine($"{monster1.Name} HP : {monster1.HP}");
Console.WriteLine($"{monster2.Name} HP : {monster2.HP}");
실행 결과
이름 없음 HP : 10
슬라임 HP : 30
new Monster()는 매개변수가 없는 생성자를 호출하고, new Monster("슬라임", 30)은 전달한 값으로 이름과 체력을 초기화합니다.
이처럼 매개변수의 개수나 자료형을 다르게 하여 여러 생성자를 정의하는 것을 생성자 오버로딩(Constructor Overloading)이라고 합니다.
여기서 주의할 점은 생성자를 직접 정의하면 매개변수가 없는 기본 생성자가 자동으로 제공되지 않는다는 것입니다.
C#에서는 인스턴스 생성자를 하나도 정의하지 않았을 때만 컴파일러가 매개변수 없는 생성자를 자동으로 제공합니다.
따라서 매개변수가 있는 생성자만 정의했다면 new Monster()는 컴파일 오류가 발생하며, 이를 사용하려면 위 예제처럼 매개변수가 없는 생성자도 직접 정의해야 합니다.
종료자(Finalizer)
객체는 생성된 이후 프로그램에서 사용되다가 더 이상 필요하지 않게 될 수 있습니다.
C#에서는 가비지 컬렉터(Garbage Collector, GC)가 더 이상 접근할 수 없는 객체의 메모리를 자동으로 회수합니다.
다만 객체가 더 이상 사용되지 않는다고 해서 즉시 메모리가 해제되는 것은 아닙니다.
이 과정과 관련된 기능이 종료자(Finalizer)입니다.
class Monster
{
~Monster()
{
Console.WriteLine("Monster 종료자 호출");
}
}
종료자는 클래스 이름 앞에 ~를 붙여 작성하며, 반환 형식과 매개변수를 사용하지 않습니다.
생성자는 객체를 생성할 때 호출되는 반면, 종료자는 객체가 GC에 의해 정리되는 과정에서 호출될 수 있습니다.
다만 종료자는 직접 호출할 수 없으며, 실행 시점도 보장되지 않습니다.
객체에 대한 참조가 사라졌다고 해서 즉시 호출되는 것은 아니며, 프로그램이 종료되기 전까지 반드시 호출된다는 보장도 없습니다.

일반적으로 C#에서는 GC가 메모리를 관리하므로 종료자를 직접 작성할 일은 많지 않습니다.
파일이나 네트워크 연결처럼 명시적인 정리가 필요한 자원은 주로 IDisposable과 Dispose() 패턴으로 관리합니다.
정리
클래스는 객체가 가질 속성과 기능을 정의하는 형식이며, 이를 바탕으로 실제 생성된 실체가 객체입니다.
인스턴스는 해당 객체가 특정 클래스로부터 생성되었다는 관계를 강조하는 표현입니다.
클래스는 참조 형식이므로 참조 변수를 복사해도 새로운 객체가 생성되지는 않습니다.
두 변수가 같은 객체를 참조하면 데이터의 변경도 공유하지만, new로 각각 생성한 객체는 서로 독립적인 상태를 가집니다.
또한 생성자는 객체의 초기화를 담당하며, 더 이상 접근할 수 없는 객체의 메모리는 GC가 관리합니다.
이때 종료자는 호출 시점과 실행 여부가 보장되지 않는다는 점에 주의해야 합니다.
이러한 개념은 이후 얕은 복사와 깊은 복사, 정적 멤버, 상속 등 클래스와 관련된 기능을 이해하는 데 기초가 됩니다.
'기본기 학습 노트 > C# 기본기 복습' 카테고리의 다른 글
| [C#] 메서드 오버로딩과 다양한 인수 활용 방법 (0) | 2026.10.12 |
|---|---|
| [C#] ref와 out의 차이점 (0) | 2026.10.10 |
| [C#] 메서드와 매개변수 (0) | 2026.10.10 |
| [C#] Object와 박싱/언박싱 (0) | 2026.09.24 |
| [C#] 값 형식과 참조 형식 (0) | 2026.09.22 |