본문 바로가기
프로그램 개발해서 돈벌기/flutter

10. 클래스 (class) - 완전 초보 Dart 언어 기초 문법 : flutter

by ubmuhan 2022. 12. 31.
반응형

사용 툴 - DartPad

https://dartpad.dev/

 

DartPad

 

dartpad.dev

DartPad 정보 : Based on Flutter 3.3.10 Dart SDK 2.18.6

 

클래스 (class) 기본 구조

이름을 찍는 클래스와 이 클래스를 이용한 코드입니다.

void main(){
  UserInfo ui = UserInfo();
  ui.printName();
  // >> 홍길동
}

class UserInfo {
  String name = "홍길동";
  void printName() {
    print(name);
  }
}

UserInfo 클래스는 멤버 변수 name과 멤버 함수 printName을 갖고 있습니다.

클래스 사용법은 변수 사용 처럼 클래스명을 타입과 같이 사용하면 됩니다.

 

생성자(constructure)

클래스 멤버 변수에 값이 없을때는 생성자(constructure)를 선언해서 클래스 사용 시 값을 전달해 주어야 합니다.

생성자를 위해 위 코드에 UserInfoConstructure 클래스를 추가했습니다.

void main(){
  UserInfo ui = UserInfo();
  ui.printName();
  // >> 홍길동
  
  UserInfoConstructure uiSt = UserInfoConstructure("원균");
  uiSt.printName();
  // >> 원균
}

class UserInfo {
  String name = "홍길동";
  
  void printName() {
    print(name);
  }
}

class UserInfoConstructure {
  String name;
  
  UserInfoConstructure(this.name);
  
  void printName() {
    print(name);
  }
}

 

네임드 생성자 (Named Constructure)

생성자를 선언하는 방식 중 네임드 생성자 방식도 있습니다. 설명을 위해서 UserInfoConstructureNamed를 추가했습니다.

이 방식 특징은 생성자 함수 내 파라미터를 순서에 상관 없이 사용할 수 있습니다. 그러나 이 방식을 추천하지 않습니다. 위 일반적인 생성자 방식 사용을 추천합니다.

void main(){
  UserInfo ui = UserInfo();
  ui.printName();
  // >> 홍길동
  
  UserInfoConstructure uiSt = UserInfoConstructure("원균");
  uiSt.printName();
  // >> 원균
  
  UserInfoConstructureNamed uiStNamed = 
    UserInfoConstructureNamed(
    school : "성균관",
    name : "원균",
  );
  uiStNamed.printName();
  // >> name : 원균, school : 성균관
}

class UserInfo {
  String name = "홍길동";
  
  void printName() {
    print(name);
  }
}

class UserInfoConstructure {
  String name;
  
  UserInfoConstructure(this.name);
  
  void printName() {
    print(name);
  }
}

class UserInfoConstructureNamed {
  String? name;
  String? school;
  
  UserInfoConstructureNamed({String? name, String? school,})
    : this.name = name,
      this.school = school;
  
  
  void printName() {
    print("name : $name, school : $school");
  }
}

 

클래스 멤버 변수 private과 getter, setter

 클래스 멤버 변수를 외부에서 접근 못하게 할때는 private 특성을 주면 됩니다. dart에서는 멤버 변수 이름 맨 앞에 '_'를 붙여주면 됩니다.

private한 멤버 변수 접근때 getter와 setter를 사용하는 샘플 코드입니다. 보통 getter, setter 이름은 private 멤버 변수 이름 맨 압에 붙은 '_'를 빼고 씁니다.

void main(){
  UserInfo ui = UserInfo("홍길동", "성균관");
  ui.printInfo();
  // >> name : 홍길동, school : 성균관
  
  ui.name = "원군";
  print(ui.name);
  // >> 원군
  
  ui.printInfo();
  // >> name : 원군, school : 성균관
}

class UserInfo {
  String _name;
  String _school;
  
  UserInfo(this._name, this._school);
  
  void printInfo() {
    print("name : $_name, school : $_school");
  }
  
  get name {
    return _name;
  }
  
  set name(name) {
    _name = name;
  }
}

 

상속(Inheritance)

Parent 클래스를 기존 클래스 사용법 처럼 작성을 했습니다. 그리고 Child 클래스는 extends를 이용해서 Parent 클래스를 상속 받았습니다. Child 클래스는 멤버 변수 선언된게 안보이지만 생성자에 상속 받은 Parent 생성자 처럼 한개 파라미터가 보입니다.

main에서 Child 클래스는 상속 받은 parentPrint를 호출해서 사용할 수 있습니다. 그리고 Child 클래스에서 새로 정의한 childPrint 함수도 사용 가능합니다. 즉 Child 클래스는 Parent 클래스 모든 기능을 사용 가능합니다.

main 함수 내 // 2 pa.parentPrint() 함수 결과가 // 1 pa.parentPrint() 결과가 같다. 중간에 Child 클래스 사용 시 Child 클래스 생성자 저장이 super로 Parent 멤버 변수에 저장이 되지만 // 1, // 2 결과는 영향을 받지 않고 결과는 같다. 이유는 main 내에서 사용한 Parent와 Child 클래스 인스턴스가 생성한 메모리가 각기 다른곳이기 때문입니다.

void main(){
  Parent pa = Parent("홍길동");
  pa.parentPrint(); // 1
  // >> name : 홍길동, school : 성균관
  
  Child ch = Child("이순신");
  ch.parentPrint();
  // >> name : 이순신
  ch.childPrint();
  // >> child print name : 이순신
  
  pa.parentPrint(); // 2
  // >> name : 홍길동
}

class Parent {
  String _name;
  
  Parent(this._name);
  
  void parentPrint() {
    print("name : $_name");
  }
  
  get name {
    return _name;
  }
  
  set name(name) {
    _name = name;
  }
}

class Child extends Parent {
  Child(String name) :
  super(
    name = name,
  );
  
  void childPrint() {
    print("child print name : $_name");
  }
}

 

Method Overriding

클래스 내 함수를 method라고 부릅니다. method overriding은 부모로부터 상속받은 함수를 덥어 쒸워서 다시 구현한다고 생각하면 됩니다. 이때 @override 를 함수 위에 적어(Annotate) 주면 됩니다. @override를 decorator라 부릅니다.

아래 코드는 Parent 클래스 cal 메소드는 더하기를 하고 이를 상속받은 Child 클래스 cal 메소드는 곱하기로 다시 정의를 한 샘플 코드 입니다. 

void main(){
  Parent pa = Parent(5);
  print("5 + 5 = ${pa.cal()}");
  // >> 5 + 5 = 10
  
  Child ch = Child(5);
  print("5 X 5 = ${ch.cal()}");
  // >> 5 X 5 = 25
}

class Parent {
  int _num;
  
  Parent(this._num);
  
  int cal() {
    return num + num;
  }
  
  get num {
    return _num;
  }
  
  set num(num) {
    _num = num;
  }
}

class Child extends Parent {
  Child(int num) :
  super(
    num = num,
  );
  
  @override
  int cal() {
    return this.num * this.num;
  }
}

 

Cascade Operator

 
 
 
 
 
 
 

아래 코드에서 main 내 ..printNum() 과 같이 호출이 가능합니다.

void main(){
  Parent pa = Parent(5);
  print("5 + 5 = ${pa.cal()}");
  // >> 5 + 5 = 10
  
  Child ch = Child(5);
  print("5 X 5 = ${ch.cal()}");
  // >> 5 X 5 = 25
  
  new Child(10)
    ..printNum();
}

class Parent {
  int _num;
  
  Parent(this._num);
  
  int cal() {
    return num + num;
  }
  
  get num {
    return _num;
  }
  
  set num(num) {
    _num = num;
  }
}

class Child extends Parent {
  Child(int num) :
  super(
    num = num,
  );
  
  @override
  int cal() {
    return this.num * this.num;
  }
  
  void printNum() {
    print("num = ${this.num}");
  }
}
반응형

댓글