상세 컨텐츠

본문 제목

0910 TIL - C# 접근 지정자, 클래스, 상속

스파르타 코딩캠프/'24 Today I Learned

by lucar 2024. 9. 10. 21:57

본문

잠깐!!!!! 들어가기 전에 확실히 알아두자.

메소드 = 함수

필드 = 클래스 안에서 선언된 변수(구문)

클래스 = 메소드와 필드의 집합

인스턴스 = 생성자를 통해 생성된 클래스 하위 객체

 

 

이번에는 접근 지정자에 대해 공부해보자.

 

접근 지정자에는 크게

public, private, protected

3가지 종류가 있다.

 

각각 설명하자면

Public 모든 클래스에서 사용가능
Private 해당 클래스에서만 사용가능
Protected 해당 클래스와 상속받는 클래스만 사용가능

 

아니 그래서 클래스가 뭔데요?

 

바로 설명해보자면

 

클래스란 객체를 만들기 위한 설계도 같은건데

 

예를 들자면

주변 사물 중 책상을 예로 들어보자.

책상은 하나의 객체이면서 여러가지의 정보를 담고 있다.

정보라 함은 가격, 재질, 용도, 다리 수, 상판의 넓이, 제조사 등등의 여러가지가 있다.

 

이걸 일일히 변수로 표시해주기에는 코드가 길어질수록 힘들어질 것이다.

왜냐면 책상이 단 한 종류만 있는게 아니기 때문에

 

그렇다면 정보의 종류만 미리 설정해놓고 만들 때마다 정보 값만 바꿔주면 되지 않을까

에서 나온게 객체지향 프로그래밍의 클래스 기능이다.

 

코드로 예를 들어보자. RPG게임의 직업을 상상해보자.

우선 체력과 공격력이 있어야할 것이다.

using System;

public class Player
{
	string name; //이름
	int hp; //체력
	int damage; //공격력
}

내친 김에 이름도 추가해주자.

 

이제 새 플레이어를 생성해보자.

Player knight = new Player();
{
	knight.name = "곽춘팔";
	knight.hp = 100;
	knight.damage = 15;
}

 

새로운 기사 곽춘팔이 등장했다!

 

이런 식으로 생성할 수도 있지만 생성자를 통한 생성도 가능하다.

using System;

public class Player
{
	public Player(string _name, int _hp, int _damage) //필드 이름과 같은 생성자 사용
	{
		string name = _name; //이름
		int hp = _hp; //체력
		int damage = _damage; //공격력
	}
}

Player knight = new Player("서대식", 100, 15);

새로운 전사 서대식이 등장했다!

 

생성자를 사용하니 더 적은 코드로도 생성이 가능해졌다.

또한 클래스 내부에 함수를 만들면 객체명.함수로 손쉽게 사용이 가능하다.

 

예를 들면

using System;


Player knight = new Player("곽춘팔", 100, 15);
Player warrior = new Player("서대식", 100, 15);
knight.Attack(); //클래스 내부의 공격 함수 불러오기


public class Player
{
    public Player(string _name, int _hp, int _damage)
    {
        string name = _name;
        int hp = _hp;
        int damage = _damage;
    }

    public void Attack() //공격 함수
    {
        Console.WriteLine("공격했다!");
    }
}

이런 식으로 함수를 불러올 수 있게된다.

 

이제 static 구문에 대해 배워볼건데

 

간단하게 설명하면 단 하나만 존재하는 유일성을 가진다고 본다.

또한 선언과 동시에 메모리에 기록된다.

 

이게 뭔소리냐 하면

 

클래스를 통한 인스턴스를 생성하는 경우 인스턴스의 수는 최소 2개 이상일 것이다.

예를 들면 NPC나 몬스터 같은 경우가 그렇다.

NPC1, NPC2, ...

고블린, 오크, ...

위의 경우와 같이 분류는 같지만 서로 다른 정보를 가지고 있는 친구들은 인스턴스로 쓰인다.

 

하지만 플레이어는? 단 한 명만 존재한다.

Static을 선언하면 클래스 내부의 필드가 클래스에 소속되어 유일성을 가지게된다.

 

다시 예를 들자면

public class Player //플레이어
{
    string name; //이름
    int hp; //체력
    int mp; //마나
    int damage; //공격력
}

public class Enemy //몬스터
{
    int hp; //체력
    int mp; //마나
    int damage; //공격력
}

 

우선 클래스 선언을 해주고

static void main(string[] args)
{
    Enemy goblin = new Enemy(); //Enemy 인스턴스 선언
    Enemy Orc = new Enemy();
    Enemy Fairy = new Enemy();

    Player Knight = new Player(); //Player 인스턴스 Knight 선언
}

본문을 작성해줬다.

 

보시는 바와 같이 비슷한 설계도를 가지고 만들었지만

몬스터는 종류도 다양하고 각자가 가지고 있을 정보도 다르다

고블린은 체력과 공격력이 낮고

오크는 체력과 공격력이 높지만 속도가 느리며

요정은 체력과 공격력이 낮지만 회피율이 높다 등의 정보를 추가할 수 있을 것이다.

 

하지만 플레이어는 단 한 명 뿐이기에 굳이 인스턴스로 플레이어를 선언할 필요가 없다.

인스턴스 내부의 필드를 수정할 필요없이 클래스의 필드만 수정해주면 된다.

 

이런 경우 static을 붙여서 정적 선언을 해주면 인스턴스가 아닌 클래스에 소속되게 된다.

public static class Player //플레이어
{
    static string name; //이름
    static int hp; //체력
    static int mp; //마나
    static int damage; //공격력

    public static void Attack() //공격 메소드
    {
        Console.WriteLine("공격했다.");
    }
}

정적으로 선언해주면 필드도 모두 정적을 선언해주어야한다.

 

정적 선언을 하자마자 Player knight = new Player();에 에러 줄이 뜨는 걸 볼 수 있는데

더 이상 인스턴스 선언을 할 수 없고 대신 knight가 Player 클래스 그 자체가 된다.

 

knight로 공격을 하려면 knight.Attack()이 아닌 Player.Attack()으로 작성하면 되는 것이다.

 

뭔가 설명을 하면 할 수록 복잡해지는거 같은데...

 

단순하게 인스턴스가 2개 이상 필요하지 않다면 static선언을 통해 클래스 이름으로 호출할 수 있게 된다.

 

그리고 선언과 동시에 메모리에 기록된다고 했는데

간단히 말하면 프로그램이 종료될 때까지 메모리 한 구석을 차지하게 된다.

그렇기 때문에 프로그램 어디서나 참조가 가능한 장점이 있다.

 

마지막으로 상속이다.

 

부모 클래스로부터 자식 클래스로 모든 필드와 메소드를 물려주게 되며

자식 클래스는 부모의 모든 필드나 메소드를 사용할 수 있게 되는것이다.

하지만 부모는 자식 클래스의 필드나 메소드를 사용할 수 없다.

 

예를 들어보자.

 

우선 클래스를 작성해주자.

class Parent //부모 클래스
{
    int money;
    string property;
}
class Son : Parent //상속 선언 자식클래스 : 부모클래스
{
    string Company;
}

상속은 위처럼 class 자식클래스 : 부모클래스 로 선언한다.

 

이해가 쉽게 돈, 부동산, 회사로 설명해보자.

 

아들은 부모님으로부터 돈과 부동산을 상속 받지만 부모님은 아들로부터 다니는 회사를 가져올 수 없다.

인스턴스 선언으로 비교해보자.

 

보시는 바와 같이 아들은 부모로부터 돈과 부동산을 상속받았기에

자신의 클래스에는 해당 항목이 없음에도 불구하고 필드를 사용할 수 있다.

 

하지만 부모는 아들이 다니는 회사를 가져오려고 해도 에러가 발생하여 가져올 수 없다.

 

아니! 제약만 늘었잖아요! 이걸 어디다가 써요!

라고 할 수 있는데 엄청나게 유용한 기능이다.

 

다시 캐릭터를 만들어보자.

 

static void main(string[] args)
{
    NPC goblin = new NPC(); //Enemy 인스턴스 선언
    NPC Orc = new NPC();
    NPC Fairy = new NPC();

    NPC villagean = new NPC(); //똑같이 Enemy 인스턴스 선언
    villagean.isEnemy = false; //공격을 할 수 없게 함

    Player Knight = new Player(); //Player 인스턴스 Knight 선언
}

public class Player //플레이어
{
    string name; //이름
    int hp; //체력
    int mp; //마나
    int damage; //공격력
}

public class NPC : Player//NPC와 몬스터는 isEnemy로 구분
{
    public string type;
    public bool isEnemy = true;
}

 

Player로부터 모두가 공통적으로 가지고 있는 이름, 체력, 마나, 공격력을 상속받았다.

NPC와 Enemy도 하나의 클래스로 만들어 isEnemy를 통해 공격이 가능한지 설정한다면?

 

이처럼 같은 공통 정보를 가지고 있는 클래스 여러개의 합집합만 추려서 부모 클래스로 올린다면

더 적게 코딩하고 더 적은 분기점을 만들어서 효율적으로 작업할 수 있다.

 

또한 족보처럼 여러 번 상속하거나 일부만 상속받을 수도 있다.

위 사진 처럼 상속에 제한은 없으니 클래스의 공통 필드를 잘 찾아서 상속해보도록 하자

 

오늘 TIL은 여기까지!

관련글 더보기