※本記事で使用している環境
<パソコン>
機種:MacBook Air(13inch)
OS:macOS Sonoma(ver.14.5)
<ソフトウェア>
・GoogleChrome(ver.126.0.6478.127)
・DartPad(Dart 3.4.3・Flutter 3.22.2)
前回は、関数について解説しました。
今回は、クラスについて解説します。
おすすめ書籍
クラスとインスタンスとは
今回扱っているDart言語は、オブジェクト指向言語に分類されます。
オブジェクト指向とは、オブジェクト(対象となるモノ)を中心としてプログラムを構築するパラダイムです。
クジラ飛行机『プログラミング言語大全』(技術評論者)
出典
オブジェクト指向言語は、クラスとインスタンスという概念をもっています。
よく設計図にたとえられる。雛形みたいなもの。
プロパティとよばれる属性(要素)を持っている。
設計図を具現化したもの。たくさん作ることができる。
クラスのプロパティに具体的な値をいれることにより、さまざまなインスタンスを作成することができる。雛形を使って実際のプロダクトをつくるイメージ。
クラスの基礎
実際に、クラスを書いてみましょう。
クラスの名前を書くときは、最初の文字を大文字にします。
クラス名を書いたら、中括弧{ } を開き、その中に属性(プロパティ)を記述します。
クラスを書いたら、次にインスタンスを作らなければいけません。
以下のようにコードを書いてみましょう。
class Car {
String? color;
int? num;
}
void main() {
var car1 = Car();
car1.color = "white";
car1.num = 1;
print(car1.color);
}
まず、①「class Car { } 」と記述し、クラスを作っています。
そして、その中に2種類の変数を宣言しています。
これが、プロパティです。
②「var car1 = Car();」の部分では、変数 car1 を宣言し、作ったクラスを代入しています。
これによって、car1 というインスタンスが作成されました。
次の③「car1.color = “white”;」では、color プロパティに具体的な値を代入しています。
④「car1.num = 1」でも、num プロパティに 1 を代入しています。
そして最後に、print 関数を呼び出して、作ったインスタンスの color プロパティを呼び出して表示しています⑤。
作った、インスタンスのプロパティを呼び出して表示させるとき、以下のように
「${car1.color}」や「${car1.num}」のように、中括弧{ } で囲み、そのまえに $(ドルマーク)をつけることで呼び出すことができます。
class Car {
String? color;
int? num;
}
void main() {
var car1 = Car();
car1.color = "white";
car1.num = 1;
print(car1.color);
print("${car1.color} ${car1.num}");
}
うまく呼び出すことができました。
では、もう一つ違うインスタンスを作ってみましょう。
class Car {
String? color;
int? num;
}
void main() {
var car1 = Car();
car1.color = "white";
car1.num = 1;
print("${car1.color} ${car1.num}");
var car2 = Car();
car2.color = "blue";
car2.num = 2;
print("${car2.color} ${car2.num}");
}
こちらもうまく実行することができました。
しかし、先ほどから、インスタンスを作成する際、変数を宣言して空っぽのクラス名で初期化しています。
この記述がめんどくさいという方もいるでしょう。
そこで、コンストラクタが登場します。
後述するメソッドの一種。
クラスの中に記述することで、インスタンスをより簡単に作ることができるようになる。
コンストラクタを記述しますが、まずは Java 言語っぽい書き方をしてみましょう。
class Car {
String? color;
int? num;
Car(String color, int num) {
this.color = color;
this.num = num;
}
}
void main() {
var car1 = Car("white", 1);
print("${car1.color} ${car1.num}");
var car2 = Car("blue", 2);
print("${car2.color} ${car2.num}");
}
まず、コンストラクタはクラス名と同じものを書きます。
今回であれば「Car」となります。
その後ろには、括弧( ) を開いて、引数をを受け取るための変数を記述します。
「(String color, int num)」がその部分に当たります。
その後は、中括弧{ } を開いて、引数で受け取った値を、設計図(クラス)に紐づいている属性(プロパティ)に渡します。
「this.color」と「this.num」が、「String? color;」と「int? num;」に対応しています。
=(イコール)を挟んで右側に記述した「color」と「num」は、引数で受け取った「String color」と「int num」に対応しています。
以上、Javaっぽく記述しましたが、Dart でコンストラクタを作るには、以下のように記述します。
class Car {
String? color;
int? num;
Car(this.color, this.num);
}
void main() {
var car1 = Car("white", 1);
print("${car1.color} ${car1.num}");
var car2 = Car("blue", 2);
print("${car2.color} ${car2.num}");
}
Dart では、①のように受け取った引数をそのままプロパティに代入するように記述します。
そして、インスタンスを作るときは、②クラス名の括弧 ( ) の中に引数を直接入力します。
③も同様です。
メソッド
前回、何かしらの処理をまとめたものを関数というと勉強しました。
クラスの中にも、関数を生やすことができます。
それをメソッドと言います。
クラスの中に記述する関数のようなもの。
何かの処理を記述する。
では、実際にコードを書いてみましょう。
class Car {
String? color;
Car(this.color);
void run() {
print("走っています");
}
}
void main() {
var car1 = Car("white");
car1.run();
}
①のように、クラスの中に処理を記述します。
そして、②で作ったメソッドを呼び出しています。
コンストラクタと組み合わせて以下のように書くこともできます。
class Car {
String? color;
Car(this.color);
void run() {
print("$color 色の車が走っています");
}
}
void main() {
var car1 = Car("white");
car1.run();
var car2 = Car("red");
car2.run();
}
メソッドの中に、インスタンスを作る時に引数として受け取った変数を記述しています。
クラスの継承
クラスには、「継承」という概念が存在します。
オブジェクト指向言語で便利に書くための記法です。
親クラスと子クラスがあり、子クラスでは親クラスのメソッドを呼び出すことができます。
そのため、子クラスに親クラスと重複するメソッドを記述する必要がなくなります。
これを、「差分プログラミング」と言います。
以下のように、Car という親クラスを作成し、FireEngine という子クラスを作成してみましょう。
class Car {
String? color;
Car(this.color);
void run() {
print("走っています");
}
}
class FireEngine extends Car {
FireEngine(String color) : super(color);
}
void main() {
var car1 = FireEngine("red");
car1.run();
}
親クラスから継承するときは、クラス名を書いた後に①「extends 親クラス名」と記述します。
子クラスを作ったら、中にコンストラクタを書かなければなりません。
今回は、②「FireEngine(String color) : super(color);」と、親クラスのコンストラクタをそのまま使うための記述をします。
「super(color)」の部分は、4行目のコンストラクタを呼び出しています。
次に、③「var car1 = FireEngine(“white”);」と書き、インスタンスを作っています。
メソッドが継承できているかを確認するには、④「car1.run();」と記述します。
もちろん、子クラスの中でメソッドを作成することもできます。
class Car {
String? color;
Car(this.color);
void run() {
print("走っています");
}
}
class FireEngine extends Car {
FireEngine(String color) : super(color);
void stopFire() {
print("消化しています");
}
}
void main() {
var car1 = FireEngine("red");
car1.run();
car1.stopFire();
}
親クラスと子クラスのどちらのメソッドも使えることがわかりました。
最後に、インスタンス car1 を子クラス「FireEngine」を使って作成していましたが、これを「Car」という親クラスに変えてみましょう。
class Car {
String? color;
Car(this.color);
void run() {
print("走っています");
}
}
class FireEngine extends Car {
FireEngine(String color) : super(color);
void stopFire() {
print("消化しています");
}
}
void main() {
var car1 = Car("red");
car1.run();
car1.stopFire();
}
コンパイルエラーが起こってしまいました。
①「var car1 = Car(“write”)」で、親クラスを使ってインスタンスを作成しています。
しかし、「stopFire」というメソッドは、子クラスで定義したため、親クラスにはありません。
実際、②のエラーメッセージにも、「『stopFire』が定義されていません」と書かれています。
このように、親クラスにあるものを子クラスに継承することができても、その逆はできないのです。
これにて、クラスの解説を終わります。
次は、Flutter で新規プロジェクトを作成する方法の解説を行います。
コメント