티스토리 뷰

반응형

extends를 사용하여 서브 클래스를 만들고 있다. 그리고 super를 사용하여 슈퍼 클래스를 참조할 수 있다.

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}

 

 

 

멤버 재정의

서브 클래스는 인스턴스 메서드(연산자 포함), 게터와 세터를 재정의할 수 있다. @override 주석을 사용하여 멤버를 의도적으로 재정의하고 있음을 나타낼 수 있다.

class Television {
  // ···
  set contrast(int value) {...}
}

class SmartTelevision extends Television {
  @override
  set contrast(num value) {...}
  // ···
}

 

재정의하는 메서드 선언은 다음 사항을 준수해야 한다.

  • 반환 타입은 재정의되는 메서드의 반환 타입과 동일하거나, 하위 타입이어야 한다.
  • 매개변수 타입은 재정의되는 메서드의 매개변수 타입과 동일하거나, 상위 타입이어야 한다.
  • 재정의되는 메서드가 n개의 위치 매개변수를 받을 경우, 동일하게 n개의 위치 매개변수를 받아야 한다.
  • 제네릭 메서드를 비-제네릭 메서드로 재정의할 수 없다. 그리고 비-제네릭 메서드를 제네릭 메서드로 재정의할 수 없다.

 

 

타입 좁히기 - convariant 

때로는 메서드 매개변수나 인스턴스 변수의 타입을 하위로 좁히고 싶을 수 있다. 이는 일반 규칙을 위반하여 런타임 시 타입 오류를 발생시킬 수 있다. 만약 타입 오류가 발생하지 않음을 보장할 수 있다면 convariant 키워드를 사용해서 타입을 좁힐 수 있다. 이 경우, 매개변수 선언에서 convariant 키워드를 사용하면 된다.

class RGB extends int {
    // ...
}

class SmartPhone extends Television {
  @override
  set contrast(covariant RGB) { ... }
  // ...
}

 

== 재정의

==를 재정의하는 경우, Object의 hashCode의 게터도 재정의해야 한다. 

class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // Override hashCode using the static hashing methods
  // provided by the `Object` class.
  @override
  int get hashCode => Object.hash(firstName, lastName);

  // You should generally implement operator `==` if you
  // override `hashCode`.
  @override
  bool operator ==(Object other) {
    return other is Person &&
        other.firstName == firstName &&
        other.lastName == lastName;
  }
}

 

 

 

noSuchMethod()

코드가 존재하지 않는 메서드나 인스턴스 변수를 사용하려고 할 때, 이를 감지하거나 반응하기 위해 noSuchMethod()를 재정의할 수 있다.

class A {
  // noSuchMethod를 재정의하지 않으면, 
  // 존재하지 않는 멤버를 사용할 경우 NoSuchMethodError가 발생합니다.
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: '
        '${invocation.memberName}');
  }
}

 

구현되지 않은 메서드를 호출하게 되면 noSuchMethodError가 발생하면 에러가 된다. 하지만 noSuchMethod()가 재정의되어 있으면 구현되지 않은 메서드가 호출되어도 에러가 발생하지 않고 noSuchMethod()가 실행되게 된다.

 

다음 조건이 모두 만족해야만 구현되지 않은 메서드를 호출할 수 있다.

  • dynamic 타입인 경우
  • noSuchMethod가 재정의되어 있고, 구현되지 않은 메서드(추상 메서드)를 가지는 경우

 

dynamic 타입인 경우

다트의 dynamic 타입은 컴파일 타임에 타입을 검사하지 않기 때문에 구현되지 않은 메서드를 호출할 수 있게 된다. 하지만 런타임 시 구현되지 않은 메서드를 호출하게 되면 noSuchMethodError가 발생하게 된다.

 

다음 코드에서 Point는 noExistenMethod()가 구현되어 있지만, point가 dynamic 타입이라서 호출이 가능해진다.

dynamic point = Point();
point.noExistenMethod();

 

 

 

noSuchMethod가 재정의되어 있고, 구현되지 않은 메서드(추상 메서드)를 가지는 경우

구현되지 않은 메서드, 즉 추상 메서드를 상속받은 경우에는 추상 메서드를 구현하지 않으면 컴파일 에러가 발생한다.

abstract class Animal {
  void makeSound();
}

class Dog extends Animal {
  // makeSound를 구현하지 않아서 컴파일 에러가 발생한다.
}

 

하지만 noSuchMethod() 메서드를 재정의하면 추상 메서드를 구현하지 않아도 컴파일 에러가 발생하지 않는다. 

 

다음 코드는 Dog가 Animal을 상속하고 makeSound() 추상 메서드를 정의하지 않았지만, noSuchMethod() 메서드를 구현하였으므로 Dog 인스턴스에서 makeSound() 메서드를 호출하여도 컴파일 에러가 발생하지 않게 된다. 그리고 런타임 시에는 Dog는 아직 makeSound()를 구현하지 않았으므로 noSuchMethod() 메서드가 대신 호출된다.

abstract class Animal {
  void makeSound();
}

class Dog extends Animal {
  void noSuchMethod(Invocation invocation) {}
}

void main() {
  Dog dog = Dog();
  dog.makeSound();  // 호출 가능

  dynamic dynamicDog = Dog();
  dynamicDog.makeSound();  // 호출 가능
}
반응형

'다트 공식 문서 번역' 카테고리의 다른 글

다트] 열거형 타입 (enum)  (0) 2024.08.04
다트] 믹스인  (0) 2024.08.04
다트] 메서드  (0) 2024.08.01
다트] 생성자  (0) 2024.08.01
다트] 클래스  (0) 2024.07.29
댓글
공지사항