Today I Learned (250708) 4-3.
상속(Inheritance)
- 기존 클래스의 기능을 확장하여 새로운 클래스를 만드는 것
- 하나의 클래스가 다른 클래스의 속성과 메서드를 물려받는 것
ㄴ 물려주는 클래스는 부모 클래스 (Parent Class, Superclass),
물려받는 클래스는 자식 클래스 (Child Class, Subclass) 라고도 함
class [자식클래스이름] extends [부모 클래스 이름] {...}
class Person {
void eat() {
print('냠냠 !');
}
}
class Student extends Person {
void study() {
print('열공 !');
}
}
/* 부모 클래스를 확장한다는 의미에서 extends 사용
Person 부모 클래스, Student 자식 클래스
- 부모 클래스는 자식 클래스에게 자신의 모든 속성과 메서드를 상속함
class Person {
String name = '';
void eat() {
print('냠냠 !');
}
}
class Student extends Person {
void study() {
print('열공 !');
}
}
void main() {
Student student = Student();
student.name = '화춘기';
student.eat(); // 냠냠 !
student.study(); // 열공 !
}
//Student에는 name이랑 eat() 정의되어 있지 않은데, 사용할 수 있음.
- 부모 클래스는 자식 클래스에 있는 멤버(속성, 메서드)를 사용할 수 없음.
class Person {
void eat() {
print('냠냠 !');
}
}
class Student extends Person {
void study() {
print('열공 !');
}
}
void main() {
Person person = Person();
person.study(); // Error: The method 'study' isn't defined for the class 'Person'.
}
- super를 통해 자식 클래스가 부모 클래스의 속성과 메서드를 사용할 수 있음
class Person {
String name = '화춘기';
void eat() {
print('냠냠 !');
}
}
class Student extends Person {
void eatAndIntroduce() {
super.eat();
print('맛있게 먹는 ${super.name} ㅋㅋ');
}
}
void main() {
Student student = Student();
student.eatAndIntroduce();
}
/*
냠냠 !
맛있게 먹는 화춘기 ㅋㅋ
this는 그 객체를 가리킴 > this 랑 비슷하게 super는 부모 클래스를 가리킴
super.eat();을 하면 Person 에 있는 eat()이 호출되고,
super.name을 하면 Person에 있는 인스턴스 변수인 name이 들어감
- 자식 클래스는 상속 받은 속성과 메서드를 재정의(overriding) 하거나 기능을 확장할 수 있음
재정의
- 자식 클래스가 부모 클래스로부터 상속 받은 속상과 메서드를 그대로 사용하지 않고 덮어 씌우는 것
재정의 사용 언제?
- 부모 클래스에 정의되어 있는 속성이나 메서드가 마음에 안들어서 새로 재정의하고 싶을 때 사용
@override [변수이름] = [값];
class Person { String name = '화춘기'; void eat() { print('냠냠 !'); } } class Student extends Person { @override String name = '여러분'; void study() { print('열공하는 $name !'); } } void main() { Student student = Student(); student.study(); // 열공하는 여러분 ! } /* Student의 name은 Person의 name을 재정의 한 속성! Student의 name은 ‘화춘기’ 대신 ‘여러분’으로 재정의
@override [반환 타입] [함수 이름] () {...}
class Person { void eat() { print('냠냠 !'); } } class Student extends Person { @override void eat() { print('쩝쩝 !'); } } void main() { Student student = Student(); student.eat(); // 쩝쩝 ! } /* Person의 eat()을 Student에서 재정의해서 냠냠 ! 이 아니라 쩝쩝 ! 이 출력
재정의 기능 확장class Person { void eat() { print('냠냠 !'); } } class Student extends Person { @override void eat() { super.eat(); print('쩝쩝 !'); } } void main() { Student student = Student(); student.eat(); } /* 냠냠 ! 쩝쩝 ! super를 통해 기존에 정의되어 있던 메서드를 호출한 후에 재정의
상속 사용하는 이유!
- 공통적인 속성과 메서드를 부모 클래스에 정의하고,
공통되지 않는 요소들만 따로 자식 클래스에 정의해서 중복된 코드를 줄이고, 코드의 재사용성을 높일 수 있음
Q. 상속 당하지 않게 클래스를 하고 싶을 때!
→ final 사용
final
- 하나의 클래스로부터 자식 클래스를 만들 수 없도록 하는 것으로
상속 받을 수 없도록 만드는 키워드라고 생각하면 됨
final class [클래스 이름] {...}
final class Person {
void eat() {
print('냠냠 !');
}
}
class Student extends Person {
// Error: The type 'Student' must be 'base', 'final' or 'sealed' because the supertype 'Person' is 'final'.
}
/* 상속 당하지 않게 하고 싶은 클래스의 이름 옆에 final 을 붙이면
그 클래스를 상속 했을 때 오류가 남
객체 지향 프로그래밍 (Object-Oriented Programming)
- OOP 라고도 함
- 객체(Object)들을 사용하여 프로그램을 구성하는 방식
객체 지향 프로그래밍 사용 이유!
- 클래스를 통해 틀을 정의해 두고, 여러 객체를 만들기 때문에 효율적임
- 클래스를 상속 받아서 기능을 확장할 수 있기 때문에 코드를 재사용할 수 있음
- 클래스를 통해 만든 객체들이 각각 독립적으로 동작하기 때문에 특정 객체를 수정해도 부작용이 생길 일이 적음
객체 지향 프로그래밍 방식으로 작성한 예시 코드
class BMW {
String name = 'BMW';
List<String> models = ['320i', '340i', 'M3'];
void introduceName() {
print('안녕하세요, 저희는 $name 입니다 !');
}
void introduceModels() {
print('저희는 $models 이렇게 ${models.length}가지 모델을 가지고 있습니다 !');
}
}
class Benz {
String name = 'Benz';
List<String> models = ['A-Class', 'C-Class', 'E-Class', 'S-Class'];
void introduceName() {
print('안녕하세요, 저희는 $name 입니다 !');
}
void introduceModels() {
print('저희는 $models 이렇게 ${models.length}가지 모델을 가지고 있습니다 !');
}
}
void main() {
BMW bmw = BMW();
bmw.introduceName(); // 안녕하세요, 저희는 BMW 입니다 !
bmw.introduceModels(); // 저희는 [320i, 340i, M3] 이렇게 3가지 모델을 가지고 있습니다 !
Benz benz = Benz();
benz.introduceName(); // 안녕하세요, 저희는 Benz 입니다 !
benz.introduceModels(); // 저희는 [A-Class, C-Class, E-Class, S-Class] 이렇게 4가지 모델을 가지고 있습니다 !
}
//이렇게 매번 클래스를 생성해 줄 수도 있지만 중복 코드가 생겨서 효율적이지 않음
↓
class Car {
String name;
List<String> models;
Car(this.name, this.models);
void introduceName() {
print('안녕하세요, 저희는 $name 입니다 !');
}
void introduceModels() {
print('저희는 $models 이렇게 ${models.length}가지 모델을 가지고 있습니다 !');
}
}
void main() {
Car bmw = Car('BMW', ['320i', '340i', 'M3']);
print(bmw.name); // BMW
print(bmw.models); // [320i, 340i, M3]
bmw.introduceName(); // 안녕하세요, 저희는 BMW 입니다 !
bmw.introduceModels(); // 저희는 [320i, 340i, M3] 이렇게 3가지 모델을 가지고 있습니다 !
Car benz = Car('Benz', ['A-Class', 'C-Class', 'E-Class', 'S-Class']);
print(benz.name); // Benz
print(benz.models); // [A-Class, C-Class, E-Class, S-Class]
benz.introduceName(); // 안녕하세요, 저희는 Benz 입니다 !
benz.introduceModels(); // 저희는 [A-Class, C-Class, E-Class, S-Class] 이렇게 4가지 모델을 가지고 있습니다 !
}'춘기IT > 춘기개발' 카테고리의 다른 글
| 라이브러리를 이용한 확장 (3) | 2025.07.09 |
|---|---|
| 예외 처리로 코드 만들기 (1) | 2025.07.09 |
| 객체 지향 프로그래밍과 Dart (3) - 생성자 / 제네릭 (2) | 2025.07.07 |
| 객체 지향 프로그래밍과 Dart (2) - 클래스와 메서드 (0) | 2025.07.07 |
| 객체 지향 프로그래밍과 Dart (1) - 클래스와 속성 (0) | 2025.07.07 |