C#_ Unity Game programming

C# 클래스 다형성 overide,virtual

doyyy_0 2024. 1. 1. 19:59

| 다형성이란?

다형성(polymorphism)이란? 다형성(polymorphism)이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다. 

즉, 다시말해 한가지 형태로 여러가지 작업을 할수 있다는 뜻이다. C#에서는 이러한 다형성을 부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를 참조할 수 있도록 하여 구현하고 있다.

 

 

여기서 overide와 virtual로 다형성을 어떻게 구성하는지 집중적으로 탐구해 볼 것이다.

class Animal
{
    public void sleep()
    {
        Debug.Log("동물이 자다");
    }
}

class Monkey : Animal
{
    public void sleep()
    {
        Debug.Log("원숭이가 자다");
    }
    
}





public class TestScript : MonoBehaviour
{
    Animal monkey = new Monkey();

    void Start()
    {
        Debug.log(monkey.sleep());
    }

}

 

 

이러한 스크립트가 있다고 하면, 출력은 부모클래스인 Animal의 "동물이 자다"가 출력된다. 

하지만 Animal monkey = new Monkey();를 Monkey monkey  = new Monkey();로 바꾸면 자식 클래스인 Monkey의 "원숭이가 자다"가 출력된다. 이유를 살펴보려면, 상속된 클래스가 호출될 때 메모리에 어떻게 올라오는지 알면 이해하기 쉽다. 

 

|부모클래스와 자식클래스 호출 시 메모리 구조

메모리에는 Animal클래스만 호출하면 Animal클래스가 호출이되고, Monkey를 호출하면 자연스레 부모 클래스까지 호출이 된다. 따라서 Monkey를 호출하면 부모 클래스인 Animal클래스도 동시에 호출이돼서 Monkey호출로는 부모 클래스의 메소드와 자기자신의 메소드를 사용할 수 있다.

 

그런데 Animal monkey = new Monkey();는 Animal에 집중한다는 뜻이라서 부모 클래스의 메소드를 불러오고, Monkey monkey  = new Monkey();는 자기 자신의 클래스에 집중한다는 뜻이라서 자기 자신의 메소드를 불러온다. 

 

하지만 문제점은 Monkey뿐만 아니라 Tiger,Lion같은 동물 클래스도 있다면 어떻게 코드를 짜야할까?

class Animal
{
    public void sleep()
    {
        Debug.Log("동물이 자다");
    }
}

class Monkey : Animal
{
    public void sleep()
    {
        Debug.Log("원숭이가 자다");
    }
    
}

class Tiger : Animal
{
    public void sleep()
    {
        Debug.Log("호랑이가 자다");
    }

}

class Lion : Animal
{
    public void sleep()
    {
        Debug.Log("사자가 자다");
    }

}
public class TestScript : MonoBehaviour
{
    Monkey monkey = new Monkey();
    Tiger tiger = new Tiger();
    Lion lion = new Lion();
    List<Animal> animal = new List<Animal>();

    void Start()
    {
        animal.Add(monkey);
        animal.Add(tiger);
        animal.Add(lion);

        foreach(var i in animal)
        {
            i.sleep();
        }
    }

}

 

이런식으로 짜게 되면 "동물이 자다"가 세번 호출이 된다. 

따라서 리스트 형식을 이용하지 못하고 

monkey.sleep();

tiger.sleep();

lion.sleep();

이렇게 일일히 써줘야한다.

 

하지만 virtual과 overide를 사용한다면 이를 피할 수 있다.

 

(override와 virtual에 관한 설명)

https://pdy0930.tistory.com/7

 

C#, 클래스 개념 지식 : 오버로딩, 오버라이딩

| 오버로딩 오버로딩이란 함수명은 같지만 시그니쳐(매개변수 구성)를 달리해서 여러개의 함수를 사용할 수 있는 기법을 말한다. 만약 이런 기능이 없다면, 매번 다른 명의 함수명을 생각해내야

pdy0930.tistory.com

 

 

class Animal
{
    public virtual void sleep()
    {
        Debug.Log("동물이 자다");
    }
}

class Monkey : Animal
{
    public override void sleep()
    {
        Debug.Log("원숭이가 자다");
    }
    
}

 

이렇게 virtual과 override로 직접 쓴다는 것은 자식 클래스를 선언하면 자식클래스를 이용한다고 선언하는 것이나 마찬가지이다. 따라서 다음과 같이 코딩하면,

class Animal
{
    public void sleep()
    {
        Debug.Log("동물이 자다");
    }
}

class Monkey : Animal
{
    public void sleep()
    {
        Debug.Log("원숭이가 자다");
    }
    
}

class Tiger : Animal
{
    public void sleep()
    {
        Debug.Log("호랑이가 자다");
    }

}

class Lion : Animal
{
    public void sleep()
    {
        Debug.Log("사자가 자다");
    }

}
public class TestScript : MonoBehaviour
{
    Animal monkey = new Monkey();
    Animal tiger = new Tiger();
    Animal lion = new Lion();
    List<Animal> animal = new List<Animal>();

    void Start()
    {
        animal.Add(monkey);
        animal.Add(tiger);
        animal.Add(lion);

        foreach(var i in animal)
        {
            i.sleep();
        }
    }

}

 

"원숭이가 자다"

"호랑이가 자다"

"사자가 자다" 

로 출력이 된다.

 

정리하자면 virtual과 override를 사용하면 코드 가독성도 좋아질 뿐더러, 반복문으로 한번에 표현하기도 쉽다.