CodeGym /행동 /C# SELF /C#에서 메서드 오버라이드(override)하기

C#에서 메서드 오버라이드(override)하기

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

1. 소개

우리한테 동물원 동물 관리 앱이 있다고 해보자(이 예제는 지난 강의에서부터 계속 발전시켜온 거 기억하지?). Animal이라는 기본 클래스를 만들고 MakeSound라는 메서드를 넣었어. 모든 동물이 "소리 내기"를 할 수 있게 하려고.


public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("동물이 소리를 낸다.");
    }
}
        
가상 메서드가 있는 기본 클래스

근데 알고 보니 사자랑 앵무새는 소리가 완전 다르잖아. "동물이 소리를 낸다"는 너무 범용적이야. 여기서 메서드 오버라이드가 등장하지! 각 동물마다 자기만의 소리를 내게 하고 싶을 때 쓰는 거야!

2. 문법: override가 어떻게 동작하는지

기본 규칙

  • 메서드를 오버라이드하려면, 기본 클래스에서 virtual (또는 abstract)로 표시해야 해.
  • 파생 클래스에서는 똑같은 시그니처의 메서드 앞에 override 키워드를 붙여줘야 해.

예제: 사자와 앵무새

public class Lion : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("으르렁!");
    }
}

public class Parrot : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("앵무새 바보!");
    }
}

이제 동물 리스트를 만들고 각각 MakeSound를 호출하면, 각자 자기 소리를 내게 돼:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Animal()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}
// 출력:
// 으르렁!
// 앵무새 바보!
// 동물이 소리를 낸다.
중요: C#은 변수 타입이 Animal이어도, 실제( run-time) 객체 타입에 맞는 메서드 구현을 호출해!

3. 가상 호출 테이블(v-table)

virtual이랑 override를 쓰면, 컴파일러가 클래스에 "가상 메서드 테이블"(v-table)을 만들어.
기본 클래스 참조로 메서드를 호출하면 CLR이 테이블을 보고: 이 메서드가 파생 클래스에서 오버라이드됐나? 만약 그렇다면 파생 클래스 버전을 호출해.
이게 바로 "late binding"(지연 바인딩) 또는 동적 다형성의 "마법"이야.

4. 같이 써보기: 우리 앱 계속 발전시키기

클래스 하나 더 추가해보자:

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("멍멍!");
    }
}

그리고 우리 동물 관리 미니 프로그램에 써보자:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Dog()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}

이제 코드 확장성도 엄청 좋아졌고, 새로운 동물 추가하는 것도 완전 꿀잼이지!

5. 프로퍼티 오버라이드와 override의 반환값

메서드만 오버라이드할 수 있는 게 아니야. 프로퍼티나 인덱서도 가상으로 만들고 오버라이드할 수 있어.

public class Animal
{
    public virtual string Name { get; set; } = "동물";
}

public class Lion : Animal
{
    public override string Name { get; set; } = "사자";
}

이렇게 하면 특정 동물에 맞는 정보를 더 정확하게 줄 수 있어서 편해.

6. base로 기본 구현 확장하기

가끔은 기본 메서드 동작을 완전히 바꾸는 게 아니라, 거기에 뭔가 더 추가하고 싶을 때가 있지.
그럴 땐 오버라이드한 메서드 안에서 base 키워드로 기본 메서드 구현을 호출하면 돼.

public class Parrot : Animal
{
    public override void MakeSound()
    {
        base.MakeSound(); // "동물이 소리를 낸다."
        Console.WriteLine("앵무새 바보!");
    }
}

이렇게 하면 앵무새가 먼저 "동물원 소리"를 내고, 그 다음에 자기만의 "앵무새 바보!"를 외쳐.

7. 실전에서 어디에 쓰이는지

override 메커니즘은 진짜 제대로 된 C# 프로젝트에서 OOP를 쓸 때 거의 필수야.

  • 우리 동물원 동물 모델링? 이미 해봤지.
  • UI용 커스텀 컨트롤 만들기: 표준 시각적 메서드를 오버라이드해서 내 로직을 추가할 수 있어.
  • 유연한 비즈니스 로직: 기본 클래스에서 "뼈대"만 만들고, 구체적인 건 상속받은 클래스에서 구현할 수 있어.
  • 테스트랑 목(mock) 객체: 상속으로 메서드를 쉽게 "바꿔치기"해서 유닛 테스트할 수 있어.
  • 플러그인/확장: 인터페이스나 추상 기본 클래스, 여러 구현체 — 이게 다 올바른 오버라이드 덕분에 잘 돌아가는 거지.

8. sealed override와 체인에서의 가상 메서드

만약 네가 오버라이드한 메서드를 더 이상 하위 클래스에서 오버라이드 못 하게 막고 싶으면, sealed override를 쓰면 돼:

public class Base
{
    public virtual void Foo() { }
}

public class Middle : Base
{
    public sealed override void Foo() { }
}

public class Last : Middle
{
    public override void Foo() {} // 에러 — 오버라이드 불가!
}

이렇게 하면 시스템이 제대로 동작하려면 오버라이드 체인을 "닫아버릴" 수 있어.

9. 새로운 메서드 (new 키워드)

가끔은 상속받은 클래스에서 똑같은 시그니처의 메서드를 만들고 싶은데, 기본 클래스 메서드가 virtual이 아니야.
이럴 땐 new 키워드를 쓸 수 있는데 — 이건 다형성이 아니라 그냥 "가리기"야:

public class Animal
{
    public void MakeSound()
    {
        Console.WriteLine("나는 동물이야!");
    }
}

public class Cat : Animal
{
    public new void MakeSound()
    {
        Console.WriteLine("나는 고양이야!");
    }
}

Animal animal = new Cat();
animal.MakeSound(); // "나는 동물이야!"
Cat cat = new Cat();
cat.MakeSound(); // "나는 고양이야!"

여기서는 호출 시점의 변수 타입이 뭔지가 전부야! 진짜 동적 다형성을 원하면 virtual + override 조합을 꼭 써!

10. 메서드 오버라이드에서 자주 하는 실수

실수 1: virtual, abstract 또는 override로 선언되지 않은 메서드를 오버라이드하려고 함.
C#에서는 일반 메서드는 오버라이드할 수 없어. 기본 클래스에서 메서드에 특별한 한정자(virtual, abstract 또는 override)가 없으면, 파생 클래스에서 override를 쓰면 컴파일 에러가 나.

실수 2: 메서드 시그니처가 다름.
진짜 오버라이드가 되려면 이름, 반환 타입, 파라미터가 기본 클래스 메서드랑 완전히 같아야 해. 조금이라도 다르면(예를 들어 파라미터 타입이 다르면) 새로운 메서드가 만들어질 뿐, 오버라이드가 아니야.

실수 3: override 한정자를 빼먹음.
기본 클래스랑 똑같은 시그니처로 메서드를 만들었는데 override를 안 붙이면, 컴파일러는 이걸 오버라이드로 안 봐. 이건 메서드 숨기기라고 부르고(따로 다룰 거야), 이 경우 기본 타입 변수로 메서드를 호출하면 네가 만든 게 아니라 기본 메서드가 호출돼서 예상치 못한 결과가 나와.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION