subindev 님의 블로그

[Flutter] #5 Dart 기본 문법 상속과 super 키워드 본문

앱개발/Flutter

[Flutter] #5 Dart 기본 문법 상속과 super 키워드

subindev 2025. 1. 6. 14:34

Dart 프로그래밍 기초

 

1. 상속과 다형성


상속(Inheritance) 이란 ?

상속은 객체지향 프로그래밍에서 부모 클래스의 특성(속성, 메서드)을 자식 클래스에서 재사용할 수 있게 하는 기능입니다. extends 키워드를 사용하여 부모 클래스를 상속받을 수 있습니다. 상속을 통해 코드 재사용을 극대화하고, 공통 기능을 부모 클래스에 정의한 후 자식 클래스에서 확장하여 사용하게 됩니다.

 

다형성 (Polymorphism) 이란?

다형성(多形性)은 한자 그대로 여러 가지 형태를 가질 수 있는 성질을 의미합니다. 이름  그대로 어떤 객체의 속성이나 메서드가 상황에 따라 여러 가지 형태를 가질 수 있는 성질을 의미합니다.

비유적으로 표현하자면, 어떤 중년의 남성이 아내에게는 남편, 자식에게는 아버지, 부모님에게는 자식, 회사에서는 회사원, 동아리에서는 총무처럼 상황에 따라 다른 역할을 한다고 할 수 있습니다.

 

객체 지향에서의 다형성도 이와 비슷합니다. 즉, 어떤 객체의 속성이나 기능이 그 맥락에 따라 다른 역할을 수행할수 있는 객체 지향의 특성을 의미합니다. 대표적인 예로 우리가 앞서 본 메서드 오버라이딩 메서드 오버로딩(method overloading)이 있습니다. Dart에서는 메서드 오버로딩을 선택적 명명 매개변수가 대체하여 사용되므로, 메서드 오버라이딩을 이용하여 다형성을 실현할 수 있습니다.

 

다시 말해 다형성은 같은 이름의 메서드나 속성이 여러 클래스에서 다르게 동작하는 특성을 말합니다. Dart에서는 주로 메서드 오버라이딩(overriding)과 런타임 다형성(runtime polymorphism)을 통해 다형성을 구현할 수 있습니다. 이를 통해 부모 클래스 타입으로 자식 클래스를 처리할 수 있게 되어, 더 유연한 코드 작성이 가능합니다.

 

상속과 다형성의 관계

  • 상속은 부모 클래스의 속성과 메서드를 자식 클래스가 상속받아 사용하는 구조이고,
  • 다형성은 부모 클래스 타입으로 자식 클래스 객체를 처리하며, 메서드나 기능을 자식 클래스마다 다르게 동작하도록 만드는 개념입니다.
class Animal {
  String name;

  Animal(this.name) {
    print('Animal 생성자 호출 ()');
  } // Animal 클래스의 생성자
  
  // 구현부가 존재하지 않는다면 생략가능
  // Animal(this.name);

  void speak() {
    print('$name makes a sound');
  }
}

class Dog extends Animal {
  // Animal 클래스를 상속
  Dog(String name) : super(name) {
    print('Dog 생성자 호출 ()');
  } // 부모 클래스의 생성자를 호출

  @override
  void speak() {
    print('$name barks');
  }
}

void main() {
  var dog = Dog('Buddy');
  dog.speak(); // 출력: Buddy barks
}
더보기
더보기
더보기

결과

Animal 생성자 호출 ();

Dog 생성자 호출();

Buddy barks

 

 

2. Super 키워드


super 키워드는 자식이 부모의 객체를 참조할 수 있는 키워드 입니다. 부모 클래스의 생성자를 호출할 때 사용합니다. 

자식클래스에서 부모 클래스의 메서드를 호출할 때도 사용할 수 있습니다. super.메서드명( );

 

super 키워드 문법을 활용한 시나리오

// super 키워드는 자식이 부모의 캑체를 참조할 수 있는 키워드 입니다.
class Burger {
  String? name;
  Burger() {
    print('버거 생성자 호출()');
  }
}

class CheeseBurger extends Burger {
  CheeseBurger(String name) {
    print('치즈버거 생성자 호출()');
    // this.name = name;
    super.name = name;
  }
}

void main() {
  CheeseBurger ch = CheeseBurger('불고기치즈버거');
  print(' name 호출 : ${ch.name}');
  // 문제 - 사용시점, 치즈버거 생성자 호출시 인수로 전달 받은 문자열을
  // 부모 클래스인 name 변수에 저장하고 싶다면 어떻게 코들 작성하지?
}

 

Super 키워드와 이니셜라이즈 문법을 활용한 코드 시나리오

// super 키워드는 자식이 부모의 캑체를 참조할 수 있는 키워드 입니다.
class Burger {

  String? name;
  
  // 기본 생성자 - 매개변수 있다면  ....
  Burger(String? name) {
    print('버거 생성자 호출()');
    this.name = name;
  }
}

class CheeseBurger extends Burger {
  // 자식에 태어나기 전에 부모가 먼저 태어나야 자식이 존재할 수 있다.
  // dart 에서 부모 생성자에 매개변수가 있다면
  // 이니셜라이즈 키워드와 super 키워드를 통해 값을 전달 한다.
  // 이니셜라이즈 키워드를 살펴 보자.
  
  CheeseBurger(String? name) : super(name) {
    print('치즈버거 생성자 호출()');
  }
}

void main() {
  CheeseBurger burger = CheeseBurger('불고기치즈버거');
  print(burger.name);
}

확인 문제

 

문제 1

(1) Animal 클래스를 만들고, 다음 조건을 만족하세요.

 
String 타입의 name 필드를 final로 선언
 
생성자를 통해 이름을 초기화

(2) Dog 클래스를 만들고, 다음 조건을 만족하세요.

 
Animal 클래스를 상속(extends)
 
생성자에서 이니셜라이저 리스트를 사용해 부모 생성자에 name을 전달
 
bark() 라는 메서드를 만들어 "멍멍!"을 출력
 
JavaScript
복사
// 소문자연결대문자 - 카멜 // 표기법 - 파스칼 케이스 class Animal { // 상수 (final) - 한 번은 반드기 초기화 되어야 하는 변수 final String name; // 생성자 (강제성) Animal(this.name); } // Dog 는 동물 이다 <-- 다형성 class Dog extends Animal { Dog(String name) : super(name); void bark() { print('멍멍!'); } } // 코드의 시작 점 (실행 시) void main() { Dog d1 = Dog('바둑이'); print(d1.name); d1.bark(); Dog d2 = Dog('흰둥이'); print(d2.name); d2.bark(); }