달나라 노트

C# : abstract, virtual (class template 생성하기) 본문

C#/C#

C# : abstract, virtual (class template 생성하기)

CosmosProject 2022. 3. 23. 23:20
728x90
반응형

 

 

 

abstract, virtual 키워드는 class와 함께 사용해서 class format을 생성할 때 사용합니다.

 

한번 상황을 예로 들어봅시다.

 

게임을 제작하는 과정에서 여러 가지 보스 몬스터들에 대한 정보를 코드에 입력해야합니다.

 

보스 몬스터들은 당연히 모두 다른 HP, MP, 공격력, 방어력을 가지고있을겁니다.

하지만 HP, MP, 공격력, 방어력이라는 속성을 가지고있다는 것은 동일하죠.

 

그런데 보스 몬스터가 굉장히 많아서 코딩하다가 어떤 보스의 방어력을 넣어주는걸 깜빡했습니다.

그러면 굉장히 큰일이나죠.

 

그래서 abstract 같은 키워드를 이용해서 필요한 변수나 method들을 가진 template을 생성해두고 상속시키면서 사용하는겁니다.

 

아래 예시를 보시죠.

 

using System;

abstract class Boss
{
    public int hp;
    public int mp;

    public void sethp(int hp)
    {
        this.hp = hp;
    }

    public void setmp(int mp)
    {
        this.mp = mp;
    }

    public abstract void attack();
    public abstract void defense();
}

class Golem : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 100");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 30");
    }
}

class Kerberos : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 250");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 70");
    }
}



class MyProgram
{
    static void Main()
    {
        Golem golem = new Golem();
        golem.sethp(1000);
        golem.setmp(850);

        Kerberos kerberos = new Kerberos();
        kerberos.sethp(3000);
        kerberos.setmp(1200);


        // Golem info
        Console.WriteLine("Golem HP = " + golem.hp);
        Console.WriteLine("Golem MP = " + golem.mp);
        golem.attack();
        golem.defense();

        // Kerberos
        Console.WriteLine("Kerberos HP = " + kerberos.hp);
        Console.WriteLine("Kerberos MP = " + kerberos.mp);
        kerberos.attack();
        kerberos.defense();
    }
}


-- Result
Golem HP = 1000
Golem MP = 850
DPS = 100
Defense = 30

Kerberos HP = 3000
Kerberos MP = 1200
DPS = 250
Defense = 70

Golem과 Kerberos 두 보스의 HP, MP, 공격력(DPS), 방어력(Defense) 정보를 구현한 것입니다.

 

 

 

 

 

여기서의 핵심은 바로 이 부분입니다.

abstract class Boss
{
    public int hp;
    public int mp;

    public void sethp(int hp)
    {
        this.hp = hp;
    }

    public void setmp(int mp)
    {
        this.mp = mp;
    }

    public abstract void attack();
    public abstract void defense();
}

Boss라는 class를 선언하는데 이때 abstract 키워드와 함께 선언했습니다.

 

Boss class의 내용은 아래와 같습니다.

 

 

    public int hp;
    public int mp;

hp, mp를 담을 속성을 선언합니다.

 

    public void sethp(int hp)
    {
        this.hp = hp;
    }

    public void setmp(int mp)
    {
        this.mp = mp;
    }

hp, mp 값을 설정해주는 기능을 가진 method를 선언합니다.

여기서 sethp method는 hp라는 정수를 인자로 받습니다.

그리고 인자로 받은 hp 값을 this.hp에 할당합니다.

 

this.hp에서 this는 현재 class를 의미합니다. 즉, this.hp는 나 자신의 class에 있는 hp라는 이름의 속성을 의미합니다.

따라서 this.hp = hp 의 의미는 인자로 받은 hp값을 나 자신의 class에 있는 hp 속성값에 할당하라는 의미입니다.

 

mp도 마찬가지입니다.

 

 

 

    public abstract void attack();
    public abstract void defense();

공격력을 나타낼 attack method와

방어력을 나타낼 defense method를 선언합니다.

 

 

여기까지 abstract Boss class의 내용을 살펴봤습니다.

 

근데 한 가지 특이한 점은 hp/mp 속성값, attack/defense method 모두 선언만 하고 어떠한 값이나 기능은 정의해주지 않았습니다.

abstract class Boss
{
    public int hp;
    public int mp;

    public void sethp(int hp)
    {
        this.hp = hp;
    }

    public void setmp(int mp)
    {
        this.mp = mp;
    }

    public abstract void attack();
    public abstract void defense();
}

그 이유는 그것이 abstract 키워드의 특성이기 때문입니다.

 

abstract 키워드와 함께 선언된 class는 속성이나 method들을 선언만 해두고 그 기능이나 내용을 할당하지 않습니다.

말그대로 class template만 만들어두는겁니다.

 

이렇게 생성된 말 그대로 틀만 있는 class를 interface라고 합니다.

 

 

 

 

 

class Golem : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 100");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 30");
    }
}

class Kerberos : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 250");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 70");
    }
}

이렇게 만들어진 Boss class를 Golem과 Kerberos class에 상속시킵니다.

 

그리고 Golem, Kerberos class에서는 Boss class에서 정의되지 않았던 attack, defense method의 기능부분을 설정해줍니다.

 

 

 

 

    static void Main(string[] args)
    {
        Golem golem = new Golem();
        golem.sethp(1000);
        golem.setmp(850);

        Kerberos kerberos = new Kerberos();
        kerberos.sethp(3000);
        kerberos.setmp(1200);


        // Golem info
        Console.WriteLine("Golem HP = " + golem.hp);
        Console.WriteLine("Golem MP = " + golem.mp);
        golem.attack();
        golem.defense();

        // Kerberos
        Console.WriteLine("Kerberos HP = " + kerberos.hp);
        Console.WriteLine("Kerberos MP = " + kerberos.mp);
        kerberos.attack();
        kerberos.defense();
    }

Golem과 Kerberos class를 가지고 객체를 생성하며 sethp, setmp method를 이용해 hp와 mp를 설정해줍니다.

 

그러면 hp, mp 속성과 attack, defense method를 정상적으로 이용할 수 있습니다.

 

 

 

 

 

 

그러면 반드시 abstract를 써야할까요?

물론 그것은 아닙니다. abstract는 여러분이 코딩을 하면서 사용할 수 있는 옵션 중 하나일 뿐입니다.

반드시 사용해야하는 것은 아닙니다.

 

abstract 키워드와 비슷한 것이 virtual 키워드입니다.

 

사실 이 둘은 거의 비슷한데 다음과 같은 가장 큰 차이점이 있습니다.

abstract 키워드로 선언된 method는 method를 선언만 하고 내용을 정의해두지 않습니다.

virtual 키워드로 선언된 method는 method를 선언하며 그 내용을 정의해둬야 합니다.

 

아래 예시는 abstract 키워드를 전혀 사용하지 않고 virtual 키워드로 동일한 내용을 구현한 코드입니다.

 

using System;

class Boss
{
    public int hp;
    public int mp;

    public void sethp(int hp)
    {
        this.hp = hp;
    }

    public void setmp(int mp)
    {
        this.mp = mp;
    }

    public virtual void attack()
    {
        Console.WriteLine("DPS = ");
    }
    public virtual void defense()
    {
        Console.WriteLine("Defense = ");
    }
}

class Golem : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 100");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 30");
    }
}

class Kerberos : Boss
{
    public override void attack()
    {
        Console.WriteLine("DPS = 250");
    }

    public override void defense()
    {
        Console.WriteLine("Defense = 70");
    }
}



class MyProgram
{
    static void Main()
    {
        Golem golem = new Golem();
        golem.sethp(1000);
        golem.setmp(850);

        Kerberos kerberos = new Kerberos();
        kerberos.sethp(3000);
        kerberos.setmp(1200);


        // Golem info
        Console.WriteLine("Golem HP = " + golem.hp);
        Console.WriteLine("Golem MP = " + golem.mp);
        golem.attack();
        golem.defense();

        // Kerberos
        Console.WriteLine("Kerberos HP = " + kerberos.hp);
        Console.WriteLine("Kerberos MP = " + kerberos.mp);
        kerberos.attack();
        kerberos.defense();
    }
}



-- Result
Golem HP = 1000
Golem MP = 850
DPS = 100
Defense = 30

Kerberos HP = 3000
Kerberos MP = 1200
DPS = 250
Defense = 70

 

 

abstract, virtual 등 상속과 관련된 여러 키워드들은 단순히 다양한 방식들입니다.

반드시 무엇을 써야한다 라는 고정된 사고방식이 아니라 상황에 따라 개인의 코딩 취향에 따라 스스로 적절한 방식을 선택하여 코딩을 하는 것이 가장 좋은 방식이라고 생각됩니다.

 

 

 

 

 

 

728x90
반응형
Comments