Help us understand the problem. What is going on with this article?

Dart 継承を理解してみる

More than 5 years have passed since last update.

Dartの継承はそんなにむずくない。怖くないはず。まだ良くわかってないから1個ずつ理解するためにまとめる。

仕様的なはなし

  • 多段継承 多重継承しないはず
    • 追記)多段継承は普通にできます
  • interface宣言は無い。class宣言が暗黙的にinterfaceになる的なやつ
    • interfaceしたけりゃ実装無しのabstractにすればいいはず
  • Genericsが使える
  • extendsimplementsがある

Basic extends

main.dart
class Parent {
  String getName() {
    return 'parent';
  }
}

class Child extends Parent {
  String getName() {
    return "child [Not ${super.getName()}]";
  }
}

main(){
  print(new Child().getName());
  //> child [Not parent]
}

Private property

dartのprivate/publicは名前の先頭に _ があるかどうかで決まる。
protectedは無いって噂だしきっと親のprivateプロパティにはアクセスできないじゃないかな。

main.dart
class Parent {
  String _name = 'parent';
  String getName() {
    return this._name;
  }
}

class Child extends Parent {
  String getName1() {
    return "child [Not ${super.getName()}]";
  }
  String getName2() {
    return "child [Not ${super._name}}";
  }
}

main(){
  Child child = new Child();
  print(child.getName1());
  print(child.getName2());
  print(child._name);
  //> child [Not parent]
  //> child [Not parent}
  //> parent
}

あれ、アクセスできた。なんでやねん。
libraryが一緒だとアクセスできちゃうらしい。なるほど。

main.dart
import './child.dart';

main(){
  Child child = new Child();
  print(child.getName1());
  //> child [Not parent]
  print(child.getName2());
  //> Unhandled exception: Class 'Child' has no instance getter '_name'.
  print(child._name);
  //> Unhandled exception: Class 'Child' has no instance getter '_name'.
}
parent.dart
class Parent {
  String _name = 'parent';
  String getName() {
    return this._name;
  }
}
child.dart
import './parent.dart';

class Child extends Parent {
  String getName1() {
    return "child [Not ${super.getName()}]";
  }
  String getName2() {
    return "child [Not ${super._name}}";
  }
}

ちゃんとエラーでてくれる。すばら。
というか library を明示的にかかなけりゃ別library的な扱いになるのかねぇ。ファイル分割しただけなんだけど。

implements

main.dart
class Parent {
  String getName() {
    return 'parent';
  }
}

class Child implements Parent {
  String getName() {
    return "child [Not ${super.getName()}]";
  }
}

main(){
  print(new Child().getName());
  //> Unhandled exception: Super class of class 'Child' has no instance method 'getName'.
}

うん。super使えないね。

implements errors

implementsってくらいだから実装なかったら死ぬはず。

main.dart
class Parent {
  String getName();
}

class Child implements Parent {
}

main(){
  print(new Child());
  //> Instance of 'Child'
}

あれ、getNameの実装をChildに求めたはずなのに特に怒られない。
abstract class Parentとかしても関係ない。
あるぇー?

$ dartanalyzer main.dart
Analyzing [main.dart]...
[warning] Missing concrete implementation of 'Parent.getName' (/path/to/main.dart, line 5, col 7)
1 warning found.

なるほど。dartanalyzerだとエラーになるけど、コンパイル時にはエラーにならないのか。
この辺もOptional Typesの方針なのかな。

という事は、CIでdartanalyzer回すようにしないといけないだろうね。
IDEでは一応エラーになってたから、開発中に全く気づけ無いという事はなさそう。

sandbox_main.dart_-__dartBBS__-_dartBBS_-____IdeaProjects_dartBBS_-3.png

generics

main.dart
import 'dart:mirrors';

abstract class Family {
  String getName();
  String getFamilyName() {
    return 'yamada';
  }
}
class Child extends Family {
  String getName() {
    return 'taro';
  }
}
class Parent extends Family {
  String getName() {
    return 'hanako';
  }
}
class Member<T extends Family> {
  String getFullName(){
    ClassMirror cm = reflectClass(T);
    T t = cm.newInstance(const Symbol(''), []).reflectee;
    return "${t.getName()} ${t.getFamilyName()}";
  }
}
main() {
  print(new Member<Child>().getFullName());
  //> taro yamada
  print(new Member<Parent>().getFullName());
  //> hanako yamada
}

使い方として合ってるかしらんけど、こんな感じの事ができるらしい。
genericsextends周りで使う意味とかやり方とかを理解してない。
でもreflectが出てきてる時点であんま良くない気がする。

FamilyextendsしたParentChildがいて、それらを受け取る?事ができるMember<T extends Family>がいて、Memberの中からはTParentだったりChildだったりするので、reflectでインスタンス取得してアレコレする的な?

with (mix-in)

main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Parent {
  String getName() {
    return 'taro';
  }
}
class Child extends Parent with Family {
  String getName() {
    return '${super.getName()} ${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
  //> taro yamada
}

withでMix-inできるみたい。でもextendsは必ず必要。
extendsいらないような場合はObjectextendsすればいいらしい。

main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Child with Family {
  String getName() {
    return '${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
}

//>[error] The with clause cannot be used without an extends clause

ちょくwithはエラーだけど、

main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Child extends Object with Family {
  String getName() {
    return '${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
  //> yamada
}

extends Objectする事で動作を変えずに継承無しのMix-inができる。Good。

まとめ

  • 何か想像と挙動違うとこある
  • Genericsがよくわからない
  • 思ったよりむずかった
  • まだ理解が足りないので追加で勉強だなー
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away