アフィリエイト広告
アフィリエイト広告

Arduino で C++クラスを学ぶ (2) – メンバへのアクセス制限

前回は、Arduino のスケッチで、クラスを宣言し利用する手順を学びました。

そしてできたのが、下のスケッチです。2 つの LED が、同時に、独立して L チカ Flash します。

Arduino で C++クラスを学ぶ (1) – クラスの宣言
  1. class Flasher {
  2.   public:
  3.     byte ledPin;
  4.     int onTime;
  5.     int offTime;
  6.     byte ledStat;
  7.     unsigned long prevMillis;
  8.     void attach();
  9.     void update();
  10. };
  11. void Flasher::attach() {
  12.   pinMode(ledPin, OUTPUT);
  13. }
  14. void Flasher::update() {
  15.   unsigned long currMillis = millis();
  16.   if((HIGH == ledStat) && (onTime < currMillis - prevMillis)) {
  17.     ledStat = LOW;
  18.     prevMillis = currMillis;
  19.     digitalWrite(ledPin, ledStat);
  20.   }
  21.   else if((LOW == ledStat) && (offTime < currMillis - prevMillis)) {
  22.     ledStat = HIGH;
  23.     prevMillis = currMillis;
  24.     digitalWrite(ledPin, ledStat);
  25.   }
  26. }
  27. Flasher led1;
  28. Flasher led2;
  29. void setup() {
  30.   led1.ledPin = 12;
  31.   led1.onTime = 100;
  32.   led1.offTime = 400;
  33.   led1.ledStat = LOW;
  34.   led1.prevMillis = 0;
  35.   led1.attach();
  36.   led2.ledPin = 13;
  37.   led2.onTime = 350;
  38.   led2.offTime = 350;
  39.   led2.ledStat = LOW;
  40.   led2.prevMillis = 0;
  41.   led2.attach();
  42. }
  43. void loop() {
  44.   led1.update();
  45.   led2.update();
  46. }

今回はこのスケッチを基にして、クラスのメンバ (変数と関数) のアクセスの制限について、学習します。

メンバへのアクセスの制限

結論を先に言うと、一般に、メンバ変数は private、メンバ関数は public にします。

前回のスケッチでは、メンバ変数は public になっています。なので、クラスの宣言の外である setup() で、メンバ変数へ直接、値を代入できています。でも、クラスではふつう、そのようなことはしません。メンバ変数は private にして、直接には値を代入できないようにします。

じゃ、どうやって値を代入するのか?
public に指定されているメンバ関数を通して代入する方法をとります。クラスの外から不正な値が代入される、といった不具合を防ぐための、クラスのしくみです。

メンバ変数を private に指定してみましょう。

  1. class Flasher {
  2.   private:
  3.     byte ledPin;
  4.     int onTime;
  5.     int offTime;
  6.     byte ledStat = LOW;
  7.     unsigned long prevMillis = 0;
  8.   public:
  9.     void attach(byte pin);
  10.     void update(int on, int off);
  11. };

メンバ変数に private の指定を付けました。メンバ関数は public のままです。

メンバ変数の値は、メンバ関数に引数として渡すことができます。attach() にはピン番号 pin を、update() には点灯時間 on と消灯時間 off を渡すことにしましょう。(10〜11行)

残りの変数 ledStat と prevMillis はどうしましょうか?
これらは、ステートマシンの状態を記憶しておくための変数で、ひとつのインスタンスのなかでだけ生きていればよい変数です。そんな子たちは、メンバ変数の定義とともに、初期値を代入してしまいましょ。(6〜7行)

引数を使って値を渡す

メンバ関数の定義です。引数を受け取るように変更しました。

  1. void Flasher::attach(byte pin) {
  2.   ledPin = pin;
  3.   pinMode(ledPin, OUTPUT);
  4. }
  5. void Flasher::update(int on, int off) {
  6.   onTime = on;
  7.   offTime = off;
  8.   unsigned long currMillis = millis();
  9.   if((HIGH == ledStat) && (onTime < currMillis - prevMillis)) {
  10.     ledStat = LOW;
  11.     prevMillis = currMillis;
  12.     digitalWrite(ledPin, ledStat);
  13.   }
  14.   else if((LOW == ledStat) && (offTime < currMillis - prevMillis)) {
  15.     ledStat = HIGH;
  16.     prevMillis = currMillis;
  17.     digitalWrite(ledPin, ledStat);
  18.   }
  19. }

メンバ関数といっても、普通の関数と同じように、引数で必要な値を渡すことができます。attach() にはピン番号を、update() には点灯時間と消灯時間を渡しています。(14〜15、19〜21行)

その他の部分は、前回と変わりありません。

オブジェクトの生成と利用

オブジェクトの生成を行ないます。これも前回と同じ。(36〜37行)

  1. Flasher led1;
  2. Flasher led2;
  3. void setup() {
  4.   led1.attach(12);
  5.   led2.attach(13);
  6. }
  7. void loop() {
  8.   led1.update(100, 400);
  9.   led2.update(350, 350);
  10. }

メンバ関数 attach() には、LED がつながれたピン番号を引数として与えます。(40〜41行)
同様に update() には、点灯時間 onTime と消灯時間 offTime を与えました。(45〜46行)
前回のスケッチと比べると、setup() のなかがスッキリしましたね。

ちなみに、前回のように setup() 内でメンバ変数に直接、値を代入するようにして、スケッチを書き込みすると、

'byte Flasher::ledPin' is private within this context

って感じで叱られます。外からの代入ができなくなっていることがわかります。

ということで、メンバ変数を private にしたスケッチができました。L チカ Flash は、前回と同様に動作しています。
このように、クラスのなかにメンバ変数、メンバ関数をまとめ、private に指定して、外から変数の値を変更できなくすることを「カプセル化」といいます。

スケッチ – メンバへのアクセスの制限

今回できあがったスケッチです。

  1. class Flasher {
  2.   private:
  3.     byte ledPin;
  4.     int onTime;
  5.     int offTime;
  6.     byte ledStat = LOW;
  7.     unsigned long prevMillis = 0;
  8.   public:
  9.     void attach(byte pin);
  10.     void update(int on, int off);
  11. };
  12. void Flasher::attach(byte pin) {
  13.   ledPin = pin;
  14.   pinMode(ledPin, OUTPUT);
  15. }
  16. void Flasher::update(int on, int off) {
  17.   onTime = on;
  18.   offTime = off;
  19.   unsigned long currMillis = millis();
  20.   if((HIGH == ledStat) && (onTime < currMillis - prevMillis)) {
  21.     ledStat = LOW;
  22.     prevMillis = currMillis;
  23.     digitalWrite(ledPin, ledStat);
  24.   }
  25.   else if((LOW == ledStat) && (offTime < currMillis - prevMillis)) {
  26.     ledStat = HIGH;
  27.     prevMillis = currMillis;
  28.     digitalWrite(ledPin, ledStat);
  29.   }
  30. }
  31. Flasher led1;
  32. Flasher led2;
  33. void setup() {
  34.   led1.attach(12);
  35.   led2.attach(13);
  36. }
  37. void loop() {
  38.   led1.update(100, 400);
  39.   led2.update(350, 350);
  40. }

まとめ

一般に、メンバ変数は private に、メンバ関数は public に指定します。

private: や public: は「アクセス指定子」と呼ばれています。アクセス指定子を省略すると、private になります。
ちなみに、アクセス指定子には、そのほかに protected: というものもあるそうです。

クラスにメンバ変数とメンバ関数をまとめ、メンバ変数を private に指定することで外からメンバ変数にアクセスできなくすることを「カプセル化」といいます。

では次回は、コンストラクタという関数を使って、メンバ変数などを初期化する方法を学びます。

タイトルとURLをコピーしました