고정적인 위치에서 프로그램 시작부터 끝까지 남아있는 메모리 (데이터 영역에 저장된다.)
- 프로그램 시작부터 끝까지 유지되야 하는 데이터
- 어디서든 가져다 쓸 수 있음 (전역적인 접근이 가능하다)
- 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;
}
<상속>
- 부모클래스를 상속하는 자식클래스에게 부모클래스의 모든 기능을 부여
- 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 { }
}
객체의 속성이나 기능이 상황에 따라 여러가지 형태를 가질 수 있는 성질
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();
}
- 새로운 클래스를 추가하거나 확장할 때 기존 코드에 영향을 최소화함.
- 새로운 클래스를 만들 때 기존의 소스를 수정하지 않아도 됨
class Player
{
Skill skill;
public void SetSkill(Skill skill)
{
this.skill = skill;
}
public void UseSkill()
{
skill.Execute(); // skill 클래스의 다형성을 확도한 결과 진행
}
}
- 클래스 간의 의존성을 줄여 확장성은 높임
class SkillContents : Skill
{
public override void Execute()
{
base.Execute();
// 프로그램의 확장을 휘해 상위클래스를 상속하는 클래스를 개발
}
}
클래스를 정의할 당시 구체화 시킬 수 없는 기능을 추상적 표현으로 정의
- 하나 이상의 추상 메서드를 포함하는 클래스
- 클래스가 추상적인 표현을 정의하는 경우, 자식에서 구체화시켜 구현할 것을 염두하고 추상화 시킴.
- 추상클래스에서 내용을 구체화 할 수 없는 추상함수는 내용을 정의하지 않음.
- 추상클래스를 상속하는 자식클래스가 추상함수를 재정의 하여 구체화한 경우 사용가능.
추상클래스를 사용하는 이유는, 추상클래스를 상속받는 클래스가 반드시 구현해야 하는 메서드가 있을 때 사용한다.
- 상위 클래스의 인터페이스를 구현하기 위한 수단으로 사용
- 추상적인 기능을 구체화시키지 않은 경우 인스턴스 생성이 불가
- 이를 통해 자식클래스에게 추상함수를 구현하도록 강제함.
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();
}