Flutter for Beginners
Dart 객체지향 프로그래밍 - 상속(Inheritance)
Andrew's Akashic Records
2025. 2. 24. 13:07
728x90
상속(Inheritance)
상속은 부모 클래스의 속성과 메서드를 자식 클래스에서 사용할 수 있도록 하는 기능입니다.
1. 기본 상속
class Animal {
String name;
Animal(this.name);
void makeSound() {
print("$name이(가) 소리를 냅니다.");
}
}
class Dog extends Animal {
Dog(String name) : super(name);
void bark() {
print("$name이(가) 짖습니다. 🐶");
}
}
void main() {
Dog dog = Dog("멍멍이");
dog.makeSound(); // 멍멍이가 소리를 냅니다.
dog.bark(); // 멍멍이가 짖습니다. 🐶
}
- super(name);을 사용하면 부모 클래스의 생성자를 호출할 수 있습니다.
2. 메서드 오버라이딩 (Method Overriding)
자식 클래스에서 부모 클래스의 메서드를 재정의(Overriding) 할 수 있습니다.
class Animal {
void makeSound() {
print("동물이 소리를 냅니다.");
}
}
class Dog extends Animal {
@override
void makeSound() {
print("멍멍! 🐶");
}
}
void main() {
Dog dog = Dog();
dog.makeSound(); // 멍멍! 🐶
}
- @override 키워드를 사용하여 부모의 메서드를 재정의할 수 있습니다.
3. 캡슐화(Encapsulation)
Dart에서는 변수와 메서드의 접근 범위를 제한하여 데이터를 보호할 수 있습니다.
3.1 접근 제한자 (_ 언더스코어 사용)
Dart에서는 private(비공개) 변수를 만들 때 변수명 앞에 _를 붙입니다.
class BankAccount {
String owner;
double _balance; // private 변수
BankAccount(this.owner, this._balance);
void deposit(double amount) {
_balance += amount;
print("$amount원이 입금되었습니다.");
}
void showBalance() {
print("잔액: $_balance원");
}
}
void main() {
BankAccount account = BankAccount("Alice", 1000);
account.deposit(500);
account.showBalance(); // 잔액: 1500원
// account._balance = 5000; // ❌ 접근 불가 (private 변수)
}
- _balance 변수는 클래스 내부에서만 접근 가능하고, 외부에서는 직접 수정할 수 없습니다.
4. 추상 클래스와 인터페이스
Dart의 extend와 implement (추상 클래스 vs 인터페이스)
Dart에서 객체지향 프로그래밍(OOP) 을 구현할 때 extend와 implement를 사용하여 클래스를 확장할 수 있습니다.
이 두 개념은 상속(Inheritance) 과 인터페이스(Interface) 구현에서 중요한 역할을 합니다.
4.1. extend (클래스 상속)
extend를 사용하면 부모 클래스의 속성과 메서드를 상속받을 수 있습니다.
- 상속된 클래스는 부모 클래스의 모든 메서드와 변수를 그대로 사용할 수 있음.
- 필요하면 @override를 사용하여 부모 메서드를 재정의할 수 있음.
- 단일 상속만 가능 (Dart는 다중 상속을 지원하지 않음).
// 부모 클래스 (추상 클래스)
abstract class Animal {
void makeSound() {
print("동물이 소리를 냅니다.");
}
}
// 자식 클래스 (Animal을 상속)
class Dog extends Animal {
@override
void makeSound() {
print("멍멍! 🐶");
}
}
void main() {
Dog dog = Dog();
dog.makeSound(); // 멍멍! 🐶
}
- Dog 클래스는 Animal 클래스를 extend하여 모든 속성과 메서드를 상속.
- makeSound() 메서드를 @override 하여 부모 메서드를 재정의.
4.2. implement (인터페이스 구현)
implement를 사용하면 특정 클래스의 인터페이스를 구현할 수 있습니다.
- implements를 사용하면 모든 메서드를 직접 구현해야 함.
- 다중 인터페이스 구현 가능 (여러 개의 클래스 인터페이스를 구현 가능).
- 기존 클래스의 구현을 가져올 수 없고, 새롭게 모든 메서드를 정의해야 함.
// 인터페이스 역할을 하는 추상 클래스
abstract class Animal {
void makeSound(); // 반드시 구현해야 함
}
// 인터페이스를 구현하는 클래스
class Cat implements Animal {
@override
void makeSound() {
print("야옹! 🐱");
}
}
void main() {
Cat cat = Cat();
cat.makeSound(); // 야옹! 🐱
}
- implements를 사용하면 부모 클래스의 메서드를 반드시 구현해야 함.
- Cat 클래스는 Animal의 makeSound() 메서드를 구현해야 오류가 발생하지 않음.
4.3. extend vs implement 차이점 정리
특징 extend (상속) implement (인터페이스)
특징 | extend | implement |
기능 | 부모 클래스의 모든 속성과 메서드를 상속받음 | 부모 클래스의 인터페이스(메서드 정의)만 가져옴 |
메서드 구현 | 재정의(override) 가능, 안 해도 됨 | 모든 메서드를 반드시 구현해야 함 |
다중 사용 가능 여부 | 단일 상속만 가능 | 여러 개의 인터페이스 구현 가능 |
부모 클래스의 구현 | 사용 가능 (super 키워드 지원) | 부모 클래스의 구현을 사용할 수 없음 |
사용 예제 | class Dog extends Animal {} | class Dog implements Animal {} |
4.4. extend와 implement를 함께 사용하기
extend로 상속을 받고, implements로 다른 인터페이스를 추가로 구현할 수도 있습니다.
// 부모 클래스
abstract class Animal {
void eat() {
print("동물이 먹습니다.");
}
}
// 인터페이스 역할을 하는 클래스
abstract class Flyable {
void fly();
}
// Bird 클래스는 Animal을 상속(`extend`)하고 Flyable을 구현(`implements`)함
class Bird extends Animal implements Flyable {
@override
void fly() {
print("새가 날아갑니다. 🕊️");
}
}
void main() {
Bird bird = Bird();
bird.eat(); // 동물이 먹습니다. (Animal에서 상속)
bird.fly(); // 새가 날아갑니다. (Flyable에서 구현)
}
- Bird 클래스는 Animal을 상속받아(extend) eat()을 그대로 사용.
- Flyable 인터페이스를 구현(implements)하여 fly()를 직접 정의.
5. 믹스인 (Mixin)
Mixin을 사용하면 코드를 재사용할 수 있으며, 다중 상속처럼 활용할 수 있습니다.
with 키워드를 사용하여 믹스인을 추가할 수 있습니다.
mixin Swimmable {
void swim() {
print("수영할 수 있습니다! 🏊");
}
}
class Fish with Swimmable {}
void main() {
Fish fish = Fish();
fish.swim(); // 수영할 수 있습니다! 🏊
}
- mixin을 사용하면 기능을 추가하는 방식으로 코드 재사용 가능.
- extends, implements와 함께 사용하여 유연한 객체지향 프로그래밍 가능.
6. Dart 3.0 interface 키워드 추가
Dart 3.0부터 interface 키워드가 도입되어, 특정 클래스를 인터페이스로만 사용할 수 있도록 제한할 수 있습니다.
interface 클래스 예제
interface class Animal {
void makeSound();
}
class Dog implements Animal {
@override
void makeSound() {
print("멍멍! 🐶");
}
}
void main() {
Dog dog = Dog();
dog.makeSound(); // 멍멍! 🐶
}
- interface class는 반드시 implements로만 사용 가능.
- 기본 구현이 있더라도 implements한 클래스는 모든 메서드를 직접 구현해야 함.
728x90