第8回
カプセル化
クラス内部のデータを適切に隠し、外部から安全に操作する。
public
class Motor {
public:
void setSpeed(int speed);
};外部から呼び出せる。
private
class Motor {
private:
int speed;
};外部から直接アクセスできない。
protected
class Sensor {
protected:
int value;
};通常の外部コードからはアクセスできないが、派生クラスから利用できる。
アクセス範囲
| 修飾子 | クラス内部 | 派生クラス | 外部 |
|---|---|---|---|
| public | ○ | ○ | ○ |
| protected | ○ | ○ | × |
| private | ○ | × | × |
getter / setter
class Motor {
public:
void setSpeed(int speed);
int getSpeed() const;
private:
int speed;
};なぜprivateにするのか
例えば、
motor.speed = -100000;のような不正な値を外部から設定される可能性がある。そこで、
void Motor::setSpeed(int speed) {
if (speed < 0) {
speed = 0;
}
if (speed > 100) {
speed = 100;
}
this->speed = speed;
}のようにクラス内部で制限する。値を守る場所が1か所に集まるため、不正な状態が作られにくくなる。
カプセル化の本質
単に「privateを使う」ということではない。
内部の実装
↓
隠す
外部には
↓
必要な操作だけ公開するという考え方を理解する。
動かして確かめる
演習に入る前に、まずこのサンプルを動かして結果を見る。追加の部品は要らない。光るのはボードに載っている内蔵LEDで、それ以外はシリアルモニタの出力で確かめられる。code/examples/08-motor-encapsulation/を開き、pio run -t uploadで書き込んでからpio device monitorで出力を見る(手順と、外付けのLEDなどをつなぐ場合は開発環境にまとめてある)。
code/examples/08-motor-encapsulation/
├── include/
│ └── Motor.hpp public に見せるのは setSpeed / getSpeed / stop だけ
└── src/
├── Motor.cpp 範囲の制限と PWM への変換はここに閉じている
└── main.cpp#include <Arduino.h>
#include "Motor.hpp"
// モータドライバはつないでいない。結果はシリアルの出力で確かめる
Motor motor(24);
void setup() {
Serial.begin(115200);
motor.begin();
// 範囲外の値を渡しても内部で丸められる
motor.setSpeed(-100000);
Serial.println(motor.getSpeed()); // 0
motor.setSpeed(500);
Serial.println(motor.getSpeed()); // 100
}
void loop() {
}0
100確かめること。
setSpeed(-100000)でも0、setSpeed(500)でも100になる。範囲はクラスの内部で守られているspeedはprivateなので、motor.speed = 500;とは書けない。試して確かめるapply()もprivate。使う側が呼ぶ必要のない手続きは見せない- 範囲の判定を
main.cpp側に書いた場合、モータを使う場所が増えたらどうなるかを考える
演習
- 第6回の
LEDクラス、第7回のMotorクラスのメンバ変数をすべてprivateにする Motor::setSpeed()に0〜100の制限を実装する- そのクラスで「外部に本当に必要な操作」は何かを書き出す