#클래스 #static #상속 #추상클래스

sejun-Lee·2025년 3월 26일

static


고정적인 위치에서 프로그램 시작부터 끝까지 남아있는 메모리 (데이터 영역에 저장된다.)

  1. 프로그램 시작부터 끝까지 유지되야 하는 데이터
  2. 어디서든 가져다 쓸 수 있음 (전역적인 접근이 가능하다)
  3. static은 1회성 사용에는 추천하지 않는다. (메모리 낭비)

static 함수 : 전역적으로 사용이 가능한 함수 -> 전역함수

static 클래스 : 모든 뱀버변수와 맴버함수가 static인 클래스. (정적 클래스)
정적 클래스는 인스턴스로 만들수 없다 . (new를 사용할 수 없다.)


internal class Program
{
    // 시스템 설정 : 볼륨 크기 (0~100), 해상도, 화면밝기

    static class Utill
    {
        public static void Swap(ref int left, ref int right)   // static은 정적 변수로서 데이터 영역에 저장한다.
        {
            int temp = left;
            left = right;
            right = temp;
        }
    }
    

    class Player
    {
        public void Attack()
        {
            Console.WriteLine("{0} 크기로 사운드 이펙트 재생!", Setting.volume);
        }
    }

    class Monster
    {
        public int hp = 100;        // static으로 hp를 선언하면 모든 몬스터가 체력 하나를 공유한다.
        public void TakeDamage(int damage)
        {
            Console.WriteLine("몬스터가 {0}의 데미지를 입었습니다.", damage);
            hp -= damage;
            Console.WriteLine("남은 체력 : {0}", hp);
            //Console.WriteLine("{0} 크기로 피격음 재생!", Setting.volume);
        }

        
    }

    static void Main(string[] args)
    {
        Console.WriteLine("현재 시스템 볼륨은 {0} 입니다.", Setting.volume);

        Player player = new Player();
        player.Attack();

        Monster monster = new Monster();
        Monster monster2 = new Monster();

        monster.TakeDamage(10);
        monster2.TakeDamage(10);


        
    }
}

class Setting
{
    public static int volume = 100;     // static은 1회성 사용에는 추천하지 않는다!
    public static int resolution = 0;
    public static int brightness = 0;
}

상속(Inheritance)


  • 부모클래스의 모든 기능을 가지는 자식클래스를 설계하는 방법
  • is-a 관계 : 부모클래스가 자식클래스를 포함하는 상위개념일 경우 상속관계가 적합함

<상속>

  • 부모클래스를 상속하는 자식클래스에게 부모클래스의 모든 기능을 부여
  • class 자식클래스 : 부모클래스

상속 사용의미1

  • 상속을 진행하는 경우 부모클래스의 소스가 자식클래스에서 모두 적용됨
  • 부모클래스와 자식클래스의 상속관계가 적합한 경우 부모클래스에서의 기능 구현이 자식클래스에서도 어울림

상속 사용의미2

  • 업캐스팅을 통해 자식클래스는 부모클래스로 형변환이 가능합
  • 자식클래스는 부모클래스를 요구하는 곳에서 동일한 기능을 수행할 수 있음
    class Monster
    {
        protected string name;      // protected : 자식클래스에서는 접근 가능. 외부에서는 접근 불가능
        public int hp;
        public float speed;

        public void Move()      // 상속하는 자식클래스에게 부모클래스의 모든 기능을 부여
        {
            Console.WriteLine("{0} 이/가 {1} 속도로 움직입니다.", name, speed);
        }

        public void TakeDamage(int damage)
        {
            hp -= damage;
            if (hp <= 0)
            {
                Console.WriteLine("{0} 몬스터가 죽었습니다.", name);
            }
        }

    }

    // 100 종류의 몬스터가 있다고 가정
    class Slime : Monster	// : Monster 로 Monster 클래스를 상속 받음
    {
        public Slime()
        {
            name = "슬라임";
            hp = 10;
            speed = 3.5f;
        }
        public void Split()     // 자식클래스에서 자식클래스 만의 기능을 추가할 수 있음
        {
            Console.WriteLine("몸체를 두개로 분리합니다.");
        }
    }

    class Dragon : Monster	// : Monster 로 Monster 클래스를 상속 받음
    {
        public float flyingSpeed;
        public float speed;             // 부모 클래스와 똑같은 이름의 변수 사용가능.

        public Dragon()
        {
            name = "드래곤";
            hp = 100;
            speed = 10.0f;
            base.speed = 10f;          // base. 으로 부모클래스의 변수에 접근
            this.speed = 5.5f;         // 자식클래스의 변수에 접근할 때 this 키워드 사용
        }
        public void Breath()
        {
            Console.WriteLine("브래스를 뿜습니다.");
        }
    }



    class Car
    {
        public string name;
        public float speed;

        public Car(string name, float speed)
        {
            Console.WriteLine("부모클래스 생성자 호출");
            this.name = name;
            this.speed = speed;
        }
    }

    class Truck : Car
    {
        public int capacity;

        public Truck() : base("트럭", 10.0f)      // 부모클래스의 생성자 호출
        {
            Console.WriteLine("자식클래스 생성자 호출");
            capacity = 10;
        }

        public Truck(string name, float speed, int capacity) : base(name, speed)
        {
            this.capacity = capacity;
        }
    }





    static void Main(string[] args)
    {
        Truck truck = new Truck();      // 부모클래스 생성자가 먼저 호출되고 자식클래스 생성자가 호출됨



        /*********************************************************************************/

        Slime slime = new Slime();
        Dragon dragon = new Dragon();

        //부모클래스 Monster를 상속한 자식클래스는 모두 부모클래스의 기능을 가지고 있음
        slime.Move();
        dragon.Move();

        // 자식클래스는 부모클래스의 기능에 더해 자식만의 고유 기능을 추가하여 구현 가능
        slime.Split();
        dragon.Breath();

        // 업캐스팅(자동으로 가능) : 자식클래스는 부모클래스 자료형으로 암시적 형변환 가능
        Monster monster = new Slime();
        Monster monster2 = new Dragon();
        //monster2.Breath();      // 부모클래스로 형변환했을 때 자식클래스의 고유 기능은 사용 불가능
        //monster.Split();        // 부모클래스로 형변환했을 때 자식클래스의 고유 기능은 사용 불가능

        Item[] inventory = new Item[20];
        inventory[0] = new Potion();
        inventory[1] = new Weapon();

        // 다운캐스팅 (불가능한 경우가 있기 때문에 확인 후에 변환 가능)
        // is : 형변환이 가능하면 true, 불가능하면 false 반환
        if (monster is Slime)       // monster가 Slime이 맞는지 확인
        {
            //Slime slime = (Slime)monster;      
            slime.Split();
        }
        else if (monster is Dragon)     // monster가 Dragon이 맞는지 확인
        {
            //Dragon dragon = (Dragon)monster;
            dragon.Breath();
        }

        // as : 형변환이 가능하면 해당 자료형으로 변환, 불가능하면 null 반환
        Dragon dragon1 = monster as Dragon;





        Player player = new Player();
        player.Attack(slime);
        player.Attack(dragon);


        player.Test(10);
        player.Test(3.5f);

        Console.WriteLine("텍스트");       // 오버로딩의 예시
        Console.WriteLine(153);
        Console.WriteLine(true);
        Console.WriteLine(2.593);

    }
 


    sealed class Player             // sealed : 상속을 막는 키워드
    {
        public int attackPoint;

        public void Attack(Monster monster)
        {
            monster.TakeDamage(attackPoint);
        }

        public void Attack(Item item)
        {
            Console.WriteLine("아이템 파괴.");
        }

        // 함수 오버로딩 -> 함수 이름은 같지만 매개변수의 타입이나 개수가 다른 함수를 여러개 만들 수 있음
        public void Test(float value) { }
        public void Test(int value) { }

        public void UseItem(Item item)
        {

        }

    }

    //class AdvancedPlayer : Player   // sealed 로 인해 상속 불가능. 오류
    //{
    //}


    class Item
    {
        public string name;
        public string icon;
        public int weight;
    }

    class Potion : Item { }

    class Weapon : Item { }


}

다형성 (Polymorphism)


객체의 속성이나 기능이 상황에 따라 여러가지 형태를 가질 수 있는 성질

public class Car
{
    public string name;
    public int speed;

    public Car(string name, int speed)
    {
        this.name = name;
        this.speed = speed;
    }

    public void Move()
    {
        Console.WriteLine($"{name}이(가) {speed}km/h로 이동합니다.");
    }
}
  static void Main(string[] args)
{
    Car sportCar = new Car("스포츠카", 100);
    Car truck = new Car("트럭", 30);

    sportCar.Move();
    truck.Move();
}    

<가상함수와 오버라이딩>

  • 가상함수 : 부모클래스의 함수 중 자식클래스에 의해 재정의 할 수 있는 함수를 지정
  • 오버라이딩 : 부모클래스의 가상함수를 같은 함수이름과 같은 매개변수로 재정의하여 자식만의 반응을 구현
public class Skill
{
    public string name;
    public float coolTime;

    public virtual void Execute()           // virtual -> 가상함수로 자식클래스에서 재정의 가능
    {
        Console.WriteLine($"{name} 스킬을 사용합니다.");
        Console.WriteLine($"재사용 대기시간 : {coolTime}초");
    }
}

public class FireBall : Skill
{
    public FireBall()
    {
        name = "파이어볼";
        coolTime = 1.5f;
    }

    public override void Execute()          // override -> 같은 이름의 virtual 함수를 재정의 해서 쓰겠다.
    {
        base.Execute();                     // 부모에 있는 Execute 도 쓰겠다.
        Console.WriteLine("화염구 발사.");

    }
}

public class Smash : Skill
{
    public Smash()
    {
        name = "강타";
        coolTime = 3.0f;
    }

    public override void Execute()
    {
        base.Execute();                     // 부모에 있는 Execute 도 쓰겠다.
        Console.WriteLine("전방에 강력한 타격");

    }
}
static void Main(string[] args)
{
    Skill skill1 = new FireBall();
    Skill skill2 = new Smash();
    skill1.Execute();
    skill2.Execute();

}

<다형성 사용의미1>

  • 새로운 클래스를 추가하거나 확장할 때 기존 코드에 영향을 최소화함.
  • 새로운 클래스를 만들 때 기존의 소스를 수정하지 않아도 됨
class Player
{
    Skill skill;

    public void SetSkill(Skill skill)
    {
        this.skill = skill;
    }

    public void UseSkill()
    {
        skill.Execute();        // skill 클래스의 다형성을 확도한 결과 진행
    }
}

<다형성 사용의미2>

  • 클래스 간의 의존성을 줄여 확장성은 높임
class SkillContents : Skill
{
    public override void Execute()
    {
        base.Execute();
        // 프로그램의 확장을 휘해 상위클래스를 상속하는 클래스를 개발
    }
}

추상화(Abstraction)


클래스를 정의할 당시 구체화 시킬 수 없는 기능을 추상적 표현으로 정의

추상 클래스(Abstract Class)

  • 하나 이상의 추상 메서드를 포함하는 클래스
  • 클래스가 추상적인 표현을 정의하는 경우, 자식에서 구체화시켜 구현할 것을 염두하고 추상화 시킴.
  • 추상클래스에서 내용을 구체화 할 수 없는 추상함수는 내용을 정의하지 않음.
  • 추상클래스를 상속하는 자식클래스가 추상함수를 재정의 하여 구체화한 경우 사용가능.

<추상화 사용의미1>

추상클래스를 사용하는 이유는, 추상클래스를 상속받는 클래스가 반드시 구현해야 하는 메서드가 있을 때 사용한다.

<추상화 사용의미2>

  • 상위 클래스의 인터페이스를 구현하기 위한 수단으로 사용
  • 추상적인 기능을 구체화시키지 않은 경우 인스턴스 생성이 불가
  • 이를 통해 자식클래스에게 추상함수를 구현하도록 강제함.

 public abstract class Item
 {
     public abstract void Use();       // 추상 메서드 -> 자식 클래스에서 반드시 재정의 해야함. (미완성 메서드)
 }

 //public class Item
 //{
 //    public virtual void Use()       // virtual : 자식 클래스에서 재정의 가능 (가상 메서드 -> 재정의 안해도 됨)
 //    {
 //        // 이거 override 해서 아이템맘다 다양한 사용 효과 만들어줘
 //    }
 //}

 public class  Potion : Item
 {
     public override void Use()          // 부모클래스의 abstract 추상메서드를 반드시 재정의 해야함.
     {
         // 포션 사용 효과
         Console.WriteLine("포션을 사용하여 채력을 회복합니다.");
     }
 }

 public class Herb : Item
 {
     public override void Use()
     {
         // 약초 사용 효과
         Console.WriteLine("해독초를 사용하여 독을 회복합니다.");
     }
 }
 static void Main(string[] args)
 {
     Item potion = new Potion();
     potion.Use();

     Item herb = new Herb();
     herb.Use();
 }
profile
초보 개발자

0개의 댓글