클래스는 객체지향 프로그래밍에서 기본이 되는 객체에 대한 정의를 다룰 때 사용한다.
형식은 참조형식으로 객체가 만들어지면 해당 객체에 대한 관리되는 힙에 메모리가 할당되고 변수에는 개체 위치에 대한 참조만 포함하게된다. 객체의 사용이 끝나면 자동으로 사라지는 게 아니라 CLR의 garbage collecter에 의해 메모리 할당을 회수하게 된다.
경우에 따라 서로 바꿔서 사용되기도 하지만 클래스와 개체는 서로 다르다. 클래스는 개체의 형식을 정의하지만 개체 자체는 아닙니다. 개체는 클래스에 기반을 둔 구체적 엔터티이고 클래스의 인스턴스라고도 합니다.
void main(){
Customer object1 = new Customer();// 클래스에 대한 객체 생성
}
클래스를 정의하면서 클래스 내부에 클래스 이름과 같은 메소드를 만들 수 있다.
public class Test{
public Test(){
//필드값 초기화
}
public Test(int _a){
//_a으로 필드값 초기화
}
}
이러한 메소드를 생성자라고 하며, 정의하지 않으면 기본 생성자가 자동으로 생성된다.
생성자들은 클래스가 할당될 때 자동으로 실행되며, 오버로드를 활용하여 클래스 필드값에 대한 초기화를 할 수 있다.
위에서 이러한 클래스들은 모두 동적할당을 받기 때문에 사용 후, 자동으로 CLR의 가비지 컬렉터에 의해 회수된다고 언급했는데 C 나 C++ 처럼 바로 할당이 해제되는 게 아니다.
가비지 컬렉터가 실행되는 조건으로
등이 있다. 가비지 컬렉터는 메모리 할당을 수거할 때 메모리에 할당된 객체들에 따라 세대를 구분한다. 세대 구분을 하는 이유는 실제로 사용이 제대로 종료된 것인지 판단하기 위한 것으로 만약 이러한 세대 구분을 무시한다면 시스템에서 계속 사용 중인 가장 중요한 메모리를 해제해버리는 대참사가 발생한다. 그래서 세대를 분류함으로서 가비지 컬렉터가 수거할 메모리들에 대한 구분을 한다.
가비지 컬렉터에 대한 좀 더 자세한 얘기는 다음 블로그에서 확인하자.
블로그
클래스들은 자신의 속성을 다른 클래스에게 그대로 상속할 수 있다. 마치 자식이 부모를 닮아 그 특성이 이어지는 것처럼 클래스들도 이러한 특성을 상속이라는 개념으로 객체들에게 특성을 이어줄 수 있다.
public class Parent{
public int _hp = 0;
public int _mp = 0;
public string _name = "mother";
public void GotoWork(){
Console.Write("Let's get to work");
}
}
public class Child : Parent{ //Parent 클래스로부터 상속받음
public void GetData(){
_name = "child"; // 객체 필드값에 대한 재정의
Console.WriteLine($"hp = {_hp} \n mp = {_mp} \");
//필드 값을 상속받아 바로 사용할 수 있음
}
}
상속은 객체지향을 구현하는데 있어 중요한 개념이다. 상속을 통해 생산선을 높이고 코드 재활용을 높일 수 있다. 자식 클래스들이 부모 클래스의 특성을 사용하면서 상황에 따라 재정의 할 수 있기에 한 객체에서 파생된 다양한 객체를 만들 수 있으며, 그에 따른 시스템 확장성을 기대할 수 있다.
자식들에게 클래스를 상속하면서 각자의 특성에 따라 사용할 메소드들에 대한 정의가 모호해질 때가 있다. 부모에게 받은 메소드가 자식에게는 맞지 않거나 아니면 다른 방식으로 사용할 수 있기 때문에 추상화라는 개념을 사용한다.
public abstract class Parent{
public abstract GetMove(){ //abstract 선언으로 GetMove() 메소드를 추상화선언
//GetMove 메소드 기본 정의
}
}
public class Child : Parent{
public override GetMove(){ //Parent의 상속받아 반드시 override로 재정의
//GetMove 메소드 재정의
}
}