第10回 解答例

Deviceクラス構造を考える

演習の解答例。まず自分で書いてから読むこと。

共通部分を見つける

LED / Motor / Servoに共通するものを書き出すと、次の2つが残る。

  • ピン番号を持つ
  • 使う前に初期化(begin())が必要

個別の機能(on() / setSpeed() / setAngle())は共通ではないので、親クラスには置かない。

Device

include/Device.hpp
#pragma once

class Device {
public:
    Device(int pin);

    void begin();

    int getPin() const;

protected:
    int pin;        // 派生クラスから使いたいので protected
};
src/Device.cpp
#include <Arduino.h>

#include "Device.hpp"

Device::Device(int pin)
    : pin(pin) {
}

void Device::begin() {
    pinMode(pin, OUTPUT);
}

int Device::getPin() const {
    return pin;
}

派生クラス

include/LED.hpp
#pragma once

#include "Device.hpp"

class LED : public Device {
public:
    LED(int pin);

    void on();
    void off();
    void toggle();

private:
    bool state;
};
src/LED.cpp
#include <Arduino.h>

#include "LED.hpp"

LED::LED(int pin)
    : Device(pin), state(false) {     // 親のコンストラクタを先に呼ぶ
}

void LED::on() {
    state = true;
    digitalWrite(pin, HIGH);        // 親の protected メンバを使える
}

void LED::off() {
    state = false;
    digitalWrite(pin, LOW);
}

void LED::toggle() {
    if (state) {
        off();
    } else {
        on();
    }
}

is-aで確認する

関係自然に言えるか判断
LED is a Device言える継承してよい
Motor is a Device言える継承してよい
Servo is a Device言える継承してよい
Robot is a Motor言えない継承しない
Robot has a Motor言えるメンバとして持つ

この設計の限界

Deviceは共通の実装をまとめただけで、「すべてのDeviceが必ず持つべき操作」を強制してはいない。「共通の約束ごと」を決めたい場合は、第12回の抽象クラスを使う。

→ 第10回の本文に戻る