CodeGym /행동 /C# SELF /상속 문법과 base in C#

상속 문법과 base in C#

C# SELF
레벨 20, 레슨 1
사용 가능

1. 소개

이번 강의에서는 C#에서 상속 문법이 어떻게 동작하는지 알아볼 거야: 파생 클래스 선언하는 법, base 키워드가 뭔지, 그리고 그걸로 부모 클래스에 어떻게 접근하는지 배울 거야. 이걸 알면 코드 쓸 때 훨씬 편해지고, 프로그램도 더 깔끔해질 거야 (가끔은 복붙 실수 고치느라 밤새는 일도 줄어들고!).

실생활 예시 하나 들어볼게: Vehicle (탈것)라는 클래스가 있어 — 기본, 범용 설계도지. 모든 탈것은 달릴 수 있고, 색깔, 제조사 등등이 있지:

public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public void Drive()
    {
        Console.WriteLine("출발!");
    }
}
기본 클래스 Vehicle

이제 새로운 탈것 — 자동차를 추가하고 싶어. 자동차도 탈것이지만, 특징이 있지 (예: 문 개수). 색깔이나 제조사 같은 건 이미 정의되어 있는데 또 쓸 필요는 없잖아!

상속은 이렇게 말할 수 있게 해줘: "자동차는 탈것이야, 근데 추가 기능이 더 있어."

2. 자식 클래스 선언하는 법

C#에서 상속받는 클래스를 만들 때는 콜론 :을 써. 클래스 이름 뒤에 어떤 클래스를 상속받는지 적어주면 돼.


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }
}
상속 클래스 Car 선언

이렇게 읽으면 돼: Car 클래스는 Vehicle 클래스의 모든 필드와 메서드를 상속받고, 거기에 자기만의 기능(예: 문 개수)을 추가하는 거야.

참고: C#에서는 단일 상속만 지원해 (즉, 클래스는 부모 클래스를 하나만 상속받을 수 있어). 근데 interface는 몇 개든 상관없어! (이건 나중에 얘기할게).

어떻게 동작하냐고?

이렇게 선언하면:

Car myCar = new Car();

...myCar 객체는 Vehicle의 모든 필드/메서드와 자기만의 속성에 다 접근할 수 있어. 예시:

myCar.Brand = "Toyota";
myCar.Color = "파랑";
myCar.NumberOfDoors = 4;
myCar.Drive(); // 상속받은 메서드

실전 시나리오:
우리 "진화하는" 앱에서 탈것 메뉴를 만들어서, 사용자가 탈것 종류를 고르면 프로그램이 그 속성을 다 보여줄 수 있어. 새로운 탈것 타입을 추가할 때마다 코드를 최소한만 쓰면 돼!

3. 생성자 상속

파생 클래스 객체를 만들 때, 기본 클래스의 속성도 생성자로 초기화하고 싶을 때가 있지. 예를 들어, 브랜드랑 색깔을 꼭 지정하게 하고 싶을 때:


public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public Vehicle(string brand, string color)
    {
        Brand = brand;
        Color = color;
    }
}

이제 상속 클래스의 생성자에서 기본 클래스 생성자를 꼭 호출해야 해! 이럴 때 base 키워드를 써:


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors)
        : base(brand, color) // Vehicle 생성자 호출!
    {
        NumberOfDoors = numberOfDoors;
    }
}

실제로 어떻게 보일까?

Car bmw = new Car("BMW", "검정", 4);
Console.WriteLine($"{bmw.Brand}, {bmw.Color}, 문: {bmw.NumberOfDoors}");
bmw.Drive(); // 여전히 동작!

결국 bmw는 자동차이면서 동시에 탈것이야. 부모의 기억을 갖고 있지.

4. base와 this의 차이

C#에는 클래스 멤버를 다룰 때 this와 base 두 키워드가 있어.

  • this — 현재 객체(자기 자신의 필드나 메서드)에 접근할 때 써.
  • base — 기본 클래스의 멤버(즉, 부모)에 접근할 때 써.

언제 base를 써야 하냐고? 예를 들어, 기본 클래스의 메서드 로직을 확장하고 싶거나, 파생 클래스에서 기본 클래스를 초기화하고 싶을 때. 예시:


public class Bicycle : Vehicle
{
    public int NumberOfGears { get; set; }

    public Bicycle(string brand, string color, int gears)
        : base(brand, color)    // 기본 클래스 생성자 호출
    {
        NumberOfGears = gears;
    }

    public void ShowInfo()
    {
        // 기본 클래스 속성 사용!
        Console.WriteLine($"{Brand} ({Color}), 기어: {NumberOfGears}");
    }
}

5. 메서드에서 base 키워드

base는 생성자에서만 쓰는 게 아니야! 가끔 기본 클래스의 메서드 동작을 바꾸고 싶지만, 그 로직 일부는 그대로 쓰고 싶을 때가 있지.

예를 들어, Car 클래스의 Drive 메서드가 어떤 차를 운전하는지도 출력하게 하고 싶어:


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors) 
        : base(brand, color)
    {
        NumberOfDoors = numberOfDoors;
    }

    public void DriveCar()
    {
        base.Drive(); // 기본 구현 호출
        Console.WriteLine($"운전 중: {Brand}, 문 {NumberOfDoors}개!");
    }
}

설명:
base.Drive(); 호출은 이렇게 말하는 거야: "아빠, 네 얘기 먼저 해주고, 내가 디테일 좀 더할게!" 그래서 DriveCar()를 호출하면 이렇게 출력돼:

출발!
운전 중: BMW, 문 4개!

메서드 오버라이드(override)는 다음 강의에서 다룰 거야 :P

6. 상속 구조도

클래스 간 관계를 시각화해보자. 간단한 그림이야 (UML은 아침에 보면 무섭잖아!):

Vehicle (기본)
   /         \
Car      Bicycle
  • 화살표는 항상 파생 클래스에서 기본 클래스로 향해.
  • 모든 자식 클래스는 public/protected 멤버에 접근할 수 있어.

public, protected, private 차이

헷갈리지 말라고 짧게 정리!
파생 클래스에서 보이는 건:

한정자 상속받은 클래스에서 보임?
public 응
protected 응
private 아니

자주 하는 실수:
파생 클래스에서 private 필드에 접근하려고 하는 거:


public class Vehicle
{
    private string secret = "아무도 모를 거야!";
}

public class Car : Vehicle
{
    public void RevealSecret()
    {
        Console.WriteLine(secret); // 오류! 안 보여.
    }
}
private — 기본 클래스만, 가족 비밀은 공유 안 됨!

비교: 기본 vs. 파생 클래스

Vehicle Car (상속)
Brand 있음 상속받음
Color 있음 상속받음
Drive() 있음 상속(또는 확장)
NumberOfDoors 없음 자기만의 (고유 속성)

7. 예제

간단한 "탈것 관리" 앱을 계속 만든다고 하면, 이렇게 구성할 수 있어:


public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public Vehicle(string brand, string color)
    {
        Brand = brand;
        Color = color;
    }

    public void Drive()
    {
        Console.WriteLine($"{Brand} {Color} 출발!");
    }
}

public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors)
        : base(brand, color)
    {
        NumberOfDoors = numberOfDoors;
    }

    public void ShowCar()
    {
        Console.WriteLine($"브랜드: {Brand}, 색상: {Color}, 문: {NumberOfDoors}");
    }
}

public class Bicycle : Vehicle
{
    public int NumberOfGears { get; set; }

    public Bicycle(string brand, string color, int numberOfGears)
        : base(brand, color)
    {
        NumberOfGears = numberOfGears;
    }
}

메인 메서드에서 탈것 리스트를 만들고 다양하게 출력할 수 있어:

Car ford = new Car("Ford", "빨강", 4);
ford.ShowCar();
ford.Drive();

Bicycle trek = new Bicycle("Trek", "초록", 21);
trek.Drive();

8. 실수, 특징, 그리고 약간의 농담

진짜 자주 하는 실수 — 파생 클래스에서 기본 생성자 호출을 까먹는 거. Vehicle에 매개변수 없는 생성자가 없는데 base(...) 호출 안 하면 컴파일 에러 나: 컴파일러가 "기반을 초기화 못 하겠다"고 화내. 1층 없이 2층 집 짓는 거랑 똑같아. 안 돼. 데이터를 위로 넘겨줘야 해.

두 번째 실수: 기본 클래스의 private 필드/메서드는 파생 클래스에서 안 보인다는 걸 까먹는 거. "자식"에게 뭔가 남기고 싶으면 protected를 써 (이건 다음 강의에서 더 자세히!).

그리고 제일 중요한 거: 상속은 편리하지만, 너무 복잡한 계층 구조는 만들지 마. 현실에서 상속 체인이 두세 단계 넘어가면 뭔가 잘못된 거야. 누가 누구한테 상속받았는지, 왜 이렇게 했는지 금방 헷갈려.

2
과제
C# SELF, 레벨 20, 레슨 1
잠금
기본 클래스 생성자를 사용하는 상속
기본 클래스 생성자를 사용하는 상속
2
과제
C# SELF, 레벨 20, 레슨 1
잠금
`base` 키워드를 사용해서 기본 클래스의 메서드 호출하기
`base` 키워드를 사용해서 기본 클래스의 메서드 호출하기
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION