본문 바로가기
Programming/Dart

Dart Override

by #root 2025. 3. 27.

Dart 오버라이드(Override) 개념과 예제

1. 오버라이드(Override)란?

오버라이드는 부모 클래스의 메서드를 자식 클래스에서 재정의(override)하는 것을 의미합니다. 이는 객체 지향 프로그래밍(OOP)에서 다형성을 구현하는 중요한 기법 중 하나입니다.

Dart에서 메서드를 오버라이드할 때는 @override 어노테이션을 사용하여 부모 클래스의 동일한 메서드를 재정의할 수 있습니다.


2. 오버라이드를 사용하는 이유

오버라이드를 사용하면 다음과 같은 이점이 있습니다.

  1. 기능 확장: 부모 클래스의 기본 기능을 유지하면서도, 자식 클래스에서 새로운 동작을 추가할 수 있습니다.
  2. 일관성 유지: 부모 클래스의 인터페이스를 유지하면서도, 자식 클래스에서 필요에 맞게 커스터마이징할 수 있습니다.
  3. 다형성 활용: 같은 인터페이스를 사용하여 다양한 객체를 처리할 수 있습니다.

3. 오버라이드 기본 예제

다음은 Animal 클래스를 만들고, 이를 상속받아 Dog와 Cat 클래스를 생성하는 예제입니다.

class Animal {
  void makeSound() {
    print("동물이 소리를 냅니다.");
  }
}

class Dog extends Animal {
  @override
  void makeSound() {
    print("멍멍!");
  }
}

class Cat extends Animal {
  @override
  void makeSound() {
    print("야옹!");
  }
}

void main() {
  Animal myDog = Dog();
  Animal myCat = Cat();

  myDog.makeSound(); // 멍멍!
  myCat.makeSound(); // 야옹!
}

🔹 설명

  • Animal 클래스에는 makeSound() 메서드가 존재합니다.
  • Dog와 Cat 클래스는 Animal을 상속받아 makeSound() 메서드를 오버라이드하여 각각 다른 동작을 수행합니다.
  • main() 함수에서 부모 타입인 Animal로 선언된 myDog와 myCat 객체는 자식 클래스의 makeSound() 메서드를 호출합니다.
  • 이를 통해 다형성을 활용할 수 있습니다.

4. 부모 클래스의 메서드 활용 (super 키워드)

오버라이드 시 부모 클래스의 원래 메서드를 호출해야 할 경우 super 키워드를 사용할 수 있습니다.

class Animal {
  void makeSound() {
    print("동물이 기본적으로 소리를 냅니다.");
  }
}

class Dog extends Animal {
  @override
  void makeSound() {
    super.makeSound(); // 부모 클래스의 메서드 호출
    print("멍멍!"); // 추가 동작
  }
}

void main() {
  Dog myDog = Dog();
  myDog.makeSound();
}

🔹 출력 결과

동물이 기본적으로 소리를 냅니다.
멍멍!

🔹 설명

  • Dog 클래스에서 makeSound()를 오버라이드했지만, super.makeSound();를 이용해 부모 클래스의 makeSound()를 먼저 실행합니다.
  • 그 후 추가적인 동작(멍멍!)을 수행합니다.

5. 오버라이드와 생성자 (Constructor)

Dart에서는 생성자(Constructor) 를 오버라이드할 수는 없지만, 부모 클래스의 생성자를 super 키워드로 호출하여 초기화할 수 있습니다.

class Animal {
  String name;

  Animal(this.name);

  void showName() {
    print("이 동물의 이름은 $name 입니다.");
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);

  @override
  void showName() {
    print("이 강아지의 이름은 $name 입니다.");
  }
}

void main() {
  Dog myDog = Dog("바둑이");
  myDog.showName(); // 이 강아지의 이름은 바둑이 입니다.
}

🔹 설명

  • Animal 클래스의 생성자를 사용하여 name을 초기화합니다.
  • Dog 클래스는 부모 생성자를 super(name)으로 호출하여 초기화합니다.
  • showName()을 오버라이드하여 개별적인 출력을 구현합니다.

6. 오버라이드와 Getter, Setter

Dart에서는 getter와 setter 도 오버라이드할 수 있습니다.

class Animal {
  String _name;

  Animal(this._name);

  String get name => _name;

  set name(String newName) {
    _name = newName;
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);

  @override
  String get name => "강아지: $_name";

  @override
  set name(String newName) {
    print("강아지의 이름을 $newName(으)로 변경합니다.");
    super.name = newName;
  }
}

void main() {
  Dog myDog = Dog("초코");
  print(myDog.name); // 강아지: 초코

  myDog.name = "바둑이"; // 강아지의 이름을 바둑이(으)로 변경합니다.
  print(myDog.name); // 강아지: 바둑이
}

🔹 설명

  • Animal 클래스에는 _name을 보호하고 getter와 setter를 제공합니다.
  • Dog 클래스는 getter를 오버라이드하여 강아지: 라는 문구를 추가하고, setter에서는 변경 시 메시지를 출력합니다.

7. 오버라이드와 추상 클래스 (Abstract Class)

추상 클래스에서 메서드를 정의하고, 이를 자식 클래스에서 반드시 오버라이드해야 하는 경우도 있습니다.

abstract class Animal {
  void makeSound(); // 추상 메서드
}

class Dog extends Animal {
  @override
  void makeSound() {
    print("멍멍!");
  }
}

class Cat extends Animal {
  @override
  void makeSound() {
    print("야옹!");
  }
}

void main() {
  Animal myDog = Dog();
  Animal myCat = Cat();

  myDog.makeSound(); // 멍멍!
  myCat.makeSound(); // 야옹!
}

🔹 설명

  • Animal 클래스는 추상 클래스(abstract class)로 선언되었으며, makeSound() 메서드는 구현되지 않았습니다.
  • 따라서 Dog와 Cat 클래스는 반드시 makeSound()를 오버라이드해야 합니다.
  • 추상 클래스를 활용하면 객체가 특정 동작을 반드시 구현하도록 강제할 수 있습니다.

8. 오버라이드를 활용한 실전 예제

🏦 은행 시스템 예제

class BankAccount {
  double balance;

  BankAccount(this.balance);

  void withdraw(double amount) {
    if (amount <= balance) {
      balance -= amount;
      print("$amount원을 출금했습니다. 남은 잔액: $balance원");
    } else {
      print("잔액이 부족합니다.");
    }
  }
}

class SavingsAccount extends BankAccount {
  double interestRate;

  SavingsAccount(double balance, this.interestRate) : super(balance);

  @override
  void withdraw(double amount) {
    print("저축 계좌에서는 출금할 수 없습니다.");
  }
}

void main() {
  BankAccount myAccount = BankAccount(5000);
  myAccount.withdraw(2000); // 2000원을 출금했습니다. 남은 잔액: 3000원

  SavingsAccount mySavings = SavingsAccount(10000, 0.05);
  mySavings.withdraw(3000); // 저축 계좌에서는 출금할 수 없습니다.
}

🔹 설명

  • 일반 계좌는 출금이 가능하지만, 저축 계좌는 출금을 막는 방식으로 withdraw()를 오버라이드하였습니다.

결론

Dart에서 오버라이드는 코드의 재사용성을 높이고, 다형성을 활용하는 데 필수적인 기능입니다.
이해를 돕기 위해 여러 예제를 소개했으니, 직접 실습해 보며 개념을 익혀 보세요! 🚀

'Programming > Dart' 카테고리의 다른 글

Dart Mixins  (0) 2025.03.28
Dart Interface  (0) 2025.03.27
Dart Inheritance  (1) 2025.03.25
Dart 파일 구조  (0) 2025.03.25
Dart Import  (0) 2025.03.25