前回は、クラスのメンバへのアクセス制限について学習しました。一般に、メンバ変数は private、メンバ関数は public にし、メンバ変数への値の代入はメンバ関数を通して行なうとのことでした。
できあがったスケッチは、つぎのとおり。
今回は、コンストラクタというものを学習します。コンストラクタとは、オブジェクトの生成を行なう時に、いろいろと初期化をしてくれるメンバ関数、なんだそうです。
コンストラクタを書く
コンストラクタは、オブジェクトの生成を行なう時に呼び出される特殊なメンバ関数です。特殊な、といっても関数ですから、メンバ関数と同じような、でもちょっとだけ違う書き方をします。
クラスの宣言
public なメンバ関数に、コンストラクタを宣言します。
- class Flasher {
- public:
- Flasher(byte pin, int on, int off);
コンストラクタの名前は、クラス名と同じ Flasher にします。戻り値はありませんが、void は付けません。引数は、無しでも有りでもいけます。ここでは、L チカ Flash に必要なピン番号と点灯時間、消灯時間を、引数として渡すことにしましょう。
クラスの宣言は、次のようになりました。
- class Flasher {
- private:
- byte ledPin;
- int onTime;
- int offTime;
- byte ledStat;
- unsigned long prevMillis;
- public:
- Flasher(byte pin, int on, int off);
- void update();
- };
必要なメンバ変数の値は、コンストラクタへ引数として渡すことにしましたので、メンバ関数 update() の引数は必要なくなりました。attach() がやっていたピンモードの設定は、コンストラクタが担いますので、attach() はそれ自体が必要なくなります。(9〜11行)
メンバ変数 ledStat と prevMillis に、宣言とともに初期値を代入していましたが、これもコンストラクタに任せることができますので、宣言のみにしています。(6〜7 行)
コンストラクタの定義
メンバ関数と同じように、コンストラクタも定義しましょう。コンストラクタはクラスと同じ名前で、void は付けません。コンストラクタが行なう処理は、さまざまな初期化処理、だそうです。ピンときませんが、ようするに、変数への初期値の代入とか、setup() でやっているような設定処理とか、ってあたりです。
- Flasher::Flasher(byte pin, int on, int off) {
- ledPin = pin;
- pinMode(ledPin, OUTPUT);
- onTime = on;
- offTime = off;
- ledStat = LOW;
- prevMillis = 0;
- }
引数として受け取ったピン番号で、ピンのモード設定ができちゃいます。(15〜16 行)
点灯時間、消灯時間も引数で受け取り、それぞれメンバ関数に代入します。(17〜18 行)
インスタンス内だけで使うメンバ変数 ledStat と prevMillis にも、コンストラクタで初期値を代入しましょう。(19〜20 行)
これで、メンバ関数への値の代入 (初期化) はすべて完了です。
メンバ関数
ピンモードの設定 pinMode() をコンストラクタで定義しましたので、メンバ関数 attach() はいらなくなっちゃいました。update() は、引数なしに変更します。
- void Flasher::update() {
- unsigned long currMillis = millis();
- if((HIGH == ledStat) && (onTime < currMillis - prevMillis)) {
- ledStat = LOW;
- prevMillis = currMillis;
- digitalWrite(ledPin, ledStat);
- }
- else if((LOW == ledStat) && (offTime < currMillis - prevMillis)) {
- ledStat = HIGH;
- prevMillis = currMillis;
- digitalWrite(ledPin, ledStat);
- }
- }
オブジェクトの生成
コンストラクタは、オブジェクトの生成を行なうときに呼び出されます。なので、コンストラクタの引数は、生成する変数へ渡すように記述します。
- Flasher led1(12, 100, 400);
- Flasher led2(13, 350, 350);
引数は、ピン番号と点灯時間、消灯時間の 3 つです。
クラスの利用
では、コンストラクタを定義したクラスを利用してみましょう。
- void setup() {
- }
- void loop() {
- led1.update();
- led2.update();
- }
setup() で行なっていたピンモードの設定は、コンストラクタが実行しますので、attach() も pinMode() もありません。setup() ではすることがなくなりました。
loop() では、L チカを行なうメンバ関数 update() を、インスタンスごとに呼び出すだけです。変数の代入もコンストラクタが行ないますので、引数もなくなりました。
えらく、スッキリ、しちゃいましたねぇ。
スケッチ – コンストラクタの定義
できあがったスケッチです。なんかこう、いい感じになってきましたよ。
- class Flasher {
- private:
- byte ledPin;
- int onTime;
- int offTime;
- byte ledStat;
- unsigned long prevMillis;
- public:
- Flasher(byte pin, int on, int off);
- void update();
- };
- Flasher::Flasher(byte pin, int on, int off) {
- ledPin = pin;
- pinMode(ledPin, OUTPUT);
- onTime = on;
- offTime = off;
- ledStat = LOW;
- prevMillis = 0;
- }
- void Flasher::update() {
- unsigned long currMillis = millis();
- if((HIGH == ledStat) && (onTime < currMillis - prevMillis)) {
- ledStat = LOW;
- prevMillis = currMillis;
- digitalWrite(ledPin, ledStat);
- }
- else if((LOW == ledStat) && (offTime < currMillis - prevMillis)) {
- ledStat = HIGH;
- prevMillis = currMillis;
- digitalWrite(ledPin, ledStat);
- }
- }
- Flasher led1(12, 100, 400);
- Flasher led2(13, 350, 350);
- void setup() {
- }
- void loop() {
- led1.update();
- led2.update();
- }
まとめ
コンストラクタとは、クラスからオブジェクトの生成を行なうときに、自動的に呼び出される、特殊なメンバ関数です。
コンストラクタは、クラスと同じ名前で、戻り値はありません。void も記述しません。引数を渡すことができます。
コンストラクタには、メンバ変数への初期値の代入や、ピンモードの設定などの初期化の処理を定義します。
さて、ここまできてみたら、できあがったスケッチは以前、みたような気が。ってゆーか、正直そこをめざしていた、わけで (^_^;)
次回は、以前学習したクラスのスケッチと、今回のスケッチをみくらべてみましょう。そして、インライン関数について学びます。