第5回
C++基礎
大規模なプログラムを整理するためのC++の機能を押さえる。
CとC++
C++はCを基礎として発展した言語だが、C++にはCにはない多くの機能がある。本講座では特に「大規模なプログラムを整理するための機能」に重点を置く。
const
const int maxSpeed = 100;変更してはいけない値を明示する。うっかり書き換えようとするとコンパイル時にエラーになるため、バグを早い段階で発見できる。
const参照
void print(const Sensor& sensor) {
}コピーを避けながら変更しないことを表現できる。オブジェクトを引数に渡すときの基本形として覚えておくとよい。
名前空間
namespace Motor {
void start();
}使用:
Motor::start();名前(変数・関数名)の衝突を避け、どのまとまりに属する機能なのかを示せる。Motor::start()とSensor::start()はそれぞれ異なる名前空間に属するため、名前の衝突を避けられる。
関数オーバーロード
int add(int a, int b);
float add(float a, float b);同じ関数名でも引数の型や数が異なれば複数定義できる。呼び出す側は型を意識せず同じ名前で呼べる。
動かして確かめる
演習に入る前に、まずこのサンプルを動かして結果を見る。追加の部品は要らない。光るのはボードに載っている内蔵LEDで、それ以外はシリアルモニタの出力で確かめられる。code/examples/05-cpp-basics/を開き、pio run -t uploadで書き込んでからpio device monitorで出力を見る(手順と、外付けのLEDなどをつなぐ場合は開発環境にまとめてある)。
/**
* @brief 整数どうしの加算
* @param a 左辺
* @param b 右辺
* @return 和
*/
int add(int a, int b) {
return a + b;
}
/**
* @brief 小数どうしの加算
* @param a 左辺
* @param b 右辺
* @return 和
*/
float add(float a, float b) {
return a + b;
}
/**
* @brief 測定結果を表示する
* @details const参照で受けるのでコピーが起きず、中身を書き換える心配もない。
* @param reading 測定結果
*/
void print(const Reading& reading) {
Serial.print("temp=");
Serial.print(reading.temperature);
Serial.print(" humi=");
Serial.println(reading.humidity);
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
delay(1000);
Serial.println("--- 名前空間 ---");
Sensor::begin();
Motor::begin();
Serial.println("--- オーバーロード ---");
Serial.print("add(1, 2) = ");
Serial.println(add(1, 2)); // int 版が呼ばれる → 3
Serial.print("add(1.5f, 2.5f) = ");
Serial.println(add(1.5f, 2.5f)); // float 版が呼ばれる → 4.00
// TEMP_THRESHOLD = 25.0f; // const なのでコンパイルエラーになる
}void loop() {
Reading reading = Sensor::read();
print(reading);
if (reading.temperature >= TEMP_THRESHOLD) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
delay(1000);
}--- 名前空間 ---
Sensor::begin()
Motor::begin()
--- オーバーロード ---
add(1, 2) = 3
add(1.5f, 2.5f) = 4.00
temp=29.50 humi=55.00
temp=31.00 humi=55.00
temp=32.50 humi=55.00
temp=34.00 humi=55.00確かめること。
Sensor::begin()とMotor::begin()が別のものとして呼べている。名前空間が違えば同じ名前でも衝突しないadd(1, 2)は3、add(1.5f, 2.5f)は4.00。呼ぶ側は同じ名前で書いていて、型に応じた関数が選ばれているsetup()の最後にあるTEMP_THRESHOLD = 25.0f;のコメントを外すとコンパイルエラーになる。constが書き換えを止めているprint()はconst Reading&で受けているので、コピーも書き換えも起きない- 温度が30.00を超えた周でLEDが点く。しきい値が
constの1行にまとまっている
演習:小規模プログラム
constでピン番号やしきい値を定義し、マジックナンバーを排除する- 名前空間にセンサ関連の関数をまとめてみる
add(int, int)とadd(float, float)を両方定義し、呼び分けを確認する