Dart 언어 오답노트 : 23. override

샤워실의 바보·2023년 10월 25일
0
post-thumbnail
void main() {
  TimesTwo tt = TimesTwo(2);
  print(tt.calculate());
  
  TimesFour tf = TimesFour(2);
  print(tf.calculate());
}

class TimesTwo {
  final int number;

  TimesTwo(
    this.number,
  );

  int calculate() {
    return number * 2;
  }
  
  void sayHello() {
  	print('Hello, everyone!');
  }
}

class TimesFour extends TimesTwo {
  TimesFour(
    int number,
  ) : super(number);

  
  int calculate() {
    return 4 * super.number;
  }
  
  
  void sayHello() {
  	super.sayHello();
    print('Good-bye');
  }
}

이 Dart 프로그램은 두 개의 클래스 TimesTwoTimesFour를 정의하고 main() 함수에서 이들을 사용하여 결과를 출력합니다.

override는 덮어쓰다, 우선시하다라는 사전적 의미를 지니고 있습니다. @override 표기가 필수는 아니나 코딩 컨벤션을 준수하기 위하여 쓰는 것이 좋습니다.

TimesTwo 클래스

  • final int number: 생성자를 통해 초기화되는 정수 값.
  • calculate(): number에 2를 곱한 결과를 반환하는 메소드.
  • sayHello(): 콘솔에 "Hello, everyone!"라는 메시지를 출력하는 메소드.

TimesFour 클래스

  • TimesFourTimesTwo를 상속받습니다.
  • calculate(): 오버라이드된 메소드로, 부모 클래스의 number 필드에 4를 곱한 값을 반환합니다.
  • sayHello(): 오버라이드된 메소드로, 부모 클래스의 sayHello() 메소드를 호출한 후, 콘솔에 "Good-bye"라는 메시지를 추가로 출력합니다.

main() 함수

  • TimesTwo 객체 tt를 생성하고 2를 인자로 전달합니다. calculate() 메소드를 호출하면 4를 출력합니다. (2 * 2 = 4)
  • TimesFour 객체 tf를 생성하고 2를 인자로 전달합니다. calculate() 메소드를 호출하면 8을 출력합니다. (4 * 2 = 8)
  • tt.sayHello()를 호출하면 "Hello, everyone!"가 출력됩니다.
  • tf.sayHello()를 호출하면 "Hello, everyone!"와 "Good-bye"가 차례로 출력됩니다. 이는 TimesFour 클래스에서 sayHello() 메소드를 오버라이딩하면서 super.sayHello()를 호출함으로써 부모 클래스의 sayHello() 메소드도 실행되도록 했기 때문입니다.

결과적으로, 이 프로그램을 실행하면 다음과 같은 출력을 볼 수 있습니다.

4
8
Hello, everyone!
Hello, everyone!
Good-bye

여기서 주목할 점은 TimesFour 클래스에서 calculate() 메소드를 오버라이딩할 때, 부모 클래스의 calculate() 메소드를 호출하는 대신 super.number를 사용하여 부모 클래스의 number 필드에 직접 접근하고 있다는 것입니다. 이렇게 함으로써 TimesFour 클래스는 부모 클래스의 calculate() 로직을 무시하고, 자신의 로직으로 완전히 대체합니다.

super.number를 this.number 또는 number라 쓸 수 있다고?

  
  int calculate() {
    return 4 * super.number;
  }
  
  int calculate() {
    return 4 * this.number;
  }
  
  int calculate() {
    return 4 * number;
  }

this.number나 단순히 number를 사용하는 것이 가능한 이유는, 현재 인스턴스, 즉 TimesFour 클래스의 인스턴스에 number 필드가 존재하기 때문입니다. 이 필드는 TimesTwo 클래스에서 상속받은 것입니다.

  1. this.number: this 키워드는 현재 인스턴스를 참조합니다. 따라서 this.number는 현재 인스턴스의 number 필드를 참조하게 됩니다. TimesFour 인스턴스에서는 number 필드가 직접 정의되어 있지 않고 상속받은 TimesTwo의 필드를 사용하고 있기 때문에, this.number는 상속받은 number 필드를 참조하게 됩니다.

  2. number: 클래스 내부에서 필드나 메소드를 참조할 때, this 키워드를 생략할 수 있습니다. 따라서 단순히 number라고 쓰면, 이는 this.number와 같은 의미가 됩니다. 이 경우 역시 상속받은 number 필드를 참조하게 됩니다.

super.numberthis.number (또는 단순히 number)는 다른 의미를 가질 수 있습니다. super.number는 명시적으로 부모 클래스의 number 필드를 참조하라는 것을 의미합니다. 반면, this.number 또는 number는 현재 클래스 인스턴스의 number 필드를 참조합니다. 상속받은 필드인 경우 이 둘은 같은 필드를 참조하지만, 만약 TimesFour 클래스 안에서 number 필드를 새로 정의했다면, this.number 또는 numberTimesFour 클래스의 number 필드를, super.numberTimesTwo 클래스의 number 필드를 참조하게 됩니다.

super.calculate()

void main() {
  TimesTwo tt = TimesTwo(2);
  print(tt.calculate());
  
  TimesFour tf = TimesFour(2);
  print(tf.calculate());
}

class TimesTwo {
  final int number;

  TimesTwo(
    this.number,
  );

  int calculate() {
    return number * 2;
  }
}

class TimesFour extends TimesTwo {
  TimesFour(
    int number,
  ) : super(number);

  
  int calculate() {
    return 4 * super.calculate();
  }
}

TimesFour 클래스의 calculate() 메소드는 TimesTwo 클래스의 calculate() 메소드를 호출하고, 그 결과에 4를 곱합니다.

이 프로세스는 다음과 같습니다:

  1. TimesFour 클래스의 calculate() 메소드가 호출됩니다.
  2. super.calculate()를 통해 TimesTwo 클래스의 calculate() 메소드가 호출되고, 입력받은 숫자 2에 2를 곱한 값인 4를 반환합니다.
  3. 반환된 값 4에 4를 곱하여 최종적으로 16을 반환합니다.

그러므로 tf.calculate()의 결과는 16이 됩니다.

profile
공부하는 개발자

0개의 댓글