수업 시간에 노트에 메모한 것 (오버라이드와 형변환)

공재원
∙∙조회 7

개요

상속으로 물려받은 메서드를 자식이 그대로 쓰지 않고 자기 방식으로 다시 정의하는 것을 오버라이드라고 한다.
그리고 부모 타입 변수 하나로 여러 자식을 다루면서 각자의 동작이 나오게 하는 것을 다형성이라고 한다.

Mermaid
렌더링 중...

오버로드와 오버라이드의 차이점 설명 ( 면접 단골 질문 )

구분오버로드오버라이드
무엇이 여럿인가같은 이름 · 다른 매개변수같은 이름 · 같은 매개변수
어디에 있는가같은 클래스 또는 상속 관계의 메서드들부모와 자식에 나뉘어 있음
고르는 시점컴파일할 때 인수를 보고실행할 때 객체를 보고
표기없음virtual · override

모든 클래스의 부모 object

  • C#의 모든 클래스는 아무것도 적지 않아도 object를 물려받는다.
  • 그래서 새로 만든 클래스도 처음부터 메서드 몇 개를 가지고 있다.

GetType()으로 실제 타입 보기

  • GetType()은 변수에 적힌 타입이 아니라 실제로 만들어진 객체의 타입을 돌려준다.
csharp
int number = 1234;
Console.WriteLine(number.GetType());
plain text
System.Int32

업캐스팅과 다운캐스팅 ( 캐스팅 = 형변환 )

  • 자식은 부모의 한 종류이므로, 부모 타입 변수에 자식 객체를 그대로 담을 수가 있다. 이것을 업캐스팅이라고 한다.
  • 업캐스팅은 암시적으로 가능하다.

다시 자식 타입으로 꺼내기

  • 부모 타입 변수를 자식 타입으로 되돌리는 것을 다운캐스팅이라고 한다.
  • 다운캐스팅은 명시적으로 가능하다.

⚠️주의: 다운캐스팅 실패는 컴파일할 때 걸리지 않고 실행 중에 프로그램을 멈춤. 캐스팅하기 전에 타입을 확인하는 습관이 필요함

is로 타입 확인하기

  • is연산자는 왼쪽 객체가 오른쪽 타입인지 true/ false로 알려준다. (bool형)
  • is뒤에 변수 이름을 붙이면 확인과 캐스팅을 한 번에 할 수 있다. 확인에 성공했을 때만 그 변수에 값이 담긴다.
csharp
Animal a1 = new Dog();
a1.Name = "초코";

Animal a2 = new Cat();
a2.Name = "나비";

Describe(a1);
Describe(a2);

static void Describe(Animal animal)
{
    if (animal is Dog dog)
    {
        dog.Bark();
    }
    else if (animal is Cat cat)
    {
        cat.Meow();
    }
}

as로 안전하게 캐스팅하기

  • as는 캐스팅에 실패하면 프로그램을 멈추는 대신 null을 돌려준다.
csharp
Animal a1 = new dog();

static void TryBark(Animal animal)
{
    Dog dog = animal as Dog;

    if (dog != null)
    {
        dog.Bark();
    }
    else
    {
        Console.WriteLine($"{animal.Name}: 짖을 수 없음");
    }
}
방법실패했을 때
(Dog)animal프로그램이 멈춤
animal is Dogfalse
animal is Dog dogfalse, 변수는 채워지지 않음
animal as Dognull

메서드 오버라이드

  • 자식마다 다르게 동작시키기
  • 업캐스팅을 해 두면 부모가 가진 멤버만 쓸 수 있다. 그런데 멤버가 자식마다 다르게 동작한다면 부모 타입 하나로 모두를 다룰 수 있게 된다.
  • 사용하기 위해선 부모 쪽에 virtual 자식 쪽에 override를 붙인다.
키워드붙이는 곳뜻
virtual부모 메서드자식이 다시 정의해도 됨
override자식 메서드부모의 그 메서드를 다시 정의함

virtual이 없으면

  • 부모에 virtual이 없는데 자식이 override하려 하면 컴파일이 되지 않는다.

base.로 부모 것을 함께 쓰기

  • 다시 정의하되 부모가 하던 일을 버리고 싶지 않을 때가 존재한다.
    base.메서드이름()으로 부모의 원래 메서드를 호출 할 수 있다.

여러 단계에 걸친 오버라이드

  • override한 메서드는 그 자식이 다시 override할 수 있다.

다형성

  • 오버라이드와 업캐스팅을 합치면, 서로 다른 자식들을 한 배열에 담아 같은 코드로 다룰 수 있다.
  • 다향성의 장점은 자식이 늘어날 때 드러난다.

new로 숨기기

  • 다시 정의하는 것이 아니라 가리는 것
  • virtual·override 없이 자식에 같은 이름의 메서드를 두면, 부모의 것을 가리는 것이 된다.
    의도한 것임을 밝히려면 new를 붙인다.
구분new (숨기기)override (재정의)
부모 쪽 표기필요 없음재정의 가능한 virtual·abstract·override
자식 쪽 표기newoverride
자식 타입으로 호출자식 것자식 것
부모 타입으로 호출부모 것자식 것
다형성안 됨됨

추상 클래스 (abstract)

  • 기본 동작이 마땅치 않을 때 사용하며 abstract를 쓰면 본문 없이 이름만 정하고 자식에게 구현을 강제할 수 있다.
  • 추상 클래스에는 본문 있는 메서드와 없는 메서드를 함께 둘 수 있고 필드와 생성자도 그대로 둘 수 있다.
  • 추상 클래스는 new할 수 없다.

virtual과 abstract의 차이

구분virtualabstract
부모의 본문있음없음
자식의 재정의선택필수
클래스 선언보통 클래스abstract class 여야 함
언제 쓰는가쓸 만한 기본 동작이 있음자식마다 반드시 달라야 함

sealed override

  • override한 메서드에 sealed를 붙이면 그 아래 자식이 더 이상 다시 정의하지 못한다.
  • 클래스에 붙이는 sealed는 상속 자체를 막고, selad override는 메서드 하나의 재정의만 막는다.

ToString() 재정의

  • Console.WriteLine()에 객체를 넘기면 그 객체의 ToString()이 불린다.
    재정의하지 않았으면 object의 기본 동작대로 타입 이름이 나옴
csharp
using System;

Person person = new Person("홍길동", 30);
Console.WriteLine(person);

class Person
{
    private string name;
    private int age;

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }
}  
plain text
Person
  • ToString()은 object에 virtual로 선언되어 있으므로 override할 수 있다.

Equals 와 GetHashCode

  • object의 Equals()는 기본적으로 같은 객체인지를 본다.
    필드 값이 모두 같아도 따로 만든 객체면 다르다고 답한다.
csharp
using System;

Point p1 = new Point(3, 4);
Point p2 = new Point(3, 4);
Point p3 = p1;

Console.WriteLine($"p1.Equals(p2): {p1.Equals(p2)}");
Console.WriteLine($"p1.Equals(p3): {p1.Equals(p3)}");
Console.WriteLine($"p1 == p2: {p1 == p2}");

class Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}
yaml
p1.Equals(p2): False
p1.Equals(p3): True
p1 == p2: False

⚠️ 주의: Equals()를 재정의하면서 GetHashCode()를 두지 않으면 경고 CS0659가 남

오늘의 수업에선 GetHashCode는 배우지 않았다.


수업에 잘 따라 가다가 프로퍼티, 상속, 오버라이드와 다형성에서 한 번 또 막혔다.
하지만 포기 하지 않고 꾸준히 공부할 것이다!