みなさんこんにちわ、こんばんわ

SAIです。

 

とあるセンサーと表示器を作ろうと考えていました。

 

携帯サイズの表示器に絵をかいて、

数字と

プログレスバーみたいなもので、

表示をしたいなぁと考えています。

 

 

当初、LCDで作ろうと思っていたのですが、

ドットがちょっと荒いのです。

また、文字列を表示することを目的としたものなので、

表示に限界があるのですよね。

(後述左上 懐かしの、 1602 です。)
 

 

そこで、別の表示器を探していました。

 

 

今回見つけたのは、

OELDディスプレイ

128dot×64dotだったと思います。

 

arduinoには、

この液晶(有機ELです)を制御するライブラリがあり、

どうやら線形描画ができそうです。

 

これは、丁度よさそうだぞ!

 

と思い、購入しました。

 

ポップの絵を見て。

 

 

 

で、箱を開けてびっくり。

 

SAIは、箱のサイズの液晶を想定していたのですが、

 

 

 

 

 

 

がーーん。

ちいさすぎじゃ!

 

 

大失敗です。

 

僕の少ないお小遣いが・・・

 

 

とりあえず、

買っちまったものはしょうがない。

 

先日作ったタイマーをLCDにも表示するテストをしてみたよ。

 

ちゃんと表示できてるね!

 

線も引けたので、テトリスくらいなら作れそうです。

 

 

 

・・・・

 

おもちゃが増えました。

(愚痴でした)
 

 

さて、ぼやいても仕方ないので、

新しいのを探そう。。。

 

 

 

【電子工作番外編】Z-3.C++番外編 override指定子とは・・

 

こんばんわ。

SAIです。

 

最近質問されてSAIが全く知らなかったもの

 

override指定子

 

コード上に記載されていて、

どのような役割なのか質問されました。

 

class Test:public TestBase

{

public:

   void hogehoge()override;

};

 

 

質問者:これはなぜ必要ですか?

 

 

・・・・

 

はっ?

なにこれ?

 

関数の後ろに・・・

const ではなく override?

 

 

2012年春までC++開発者だったSAIですが、

全く知りませんでした。

#割と巨大なシステムで、実質作業していたのは2011年春まで。

#以降は保守してたんで、経験はそこそこあるはずなのですが・・・

 

 

もっと偉い人に聞いてみたところ、

どうやら、子クラス側で、

オーバーライドした関数だよ!

という、明言をすることができる指定子だったらしいです。

 

 

どのように使うのか?

 

知らないので調べてみました。

※最初、overrideで検索しても全然Hitしなくて困ったのですが、

  override指定子 で検索すると、Hitしました!

 

 

 

どうやら、

overrideを書いていると、継承した関数につければ、

継承に失敗したときにエラーをはいてくれるようです。

 

つまり、ベースクラスがこんなだった時に

class  TestBase

{

public:

   void hogehoge();    //virtualではない              

   virtual void hogehoge(int aParam);    //引数がint1つ

};

 

派生クラスで以下のような関数を定義した際、

class Test:public TestBase

{

public:

   //①親がvirtualではないので再定義になりoverride不成立  

   void hogehoge()  override;

   //②引数がdouble  = オーバーロード扱いになるのでoverride不成立   

   void hogehoge(double aParam)  override;   

    //③引数がint2つ  = オーバーロード扱いになるのでoverride不成立

   void hogehoge(int aParam, int aParam)  override;

};

 

この状況下でビルドすると、

overrideを書いていない場合

 コメントで記載した通り、オーバーライドできず、

 すべて派生クラス固有の関数として定義されてしまいます。

 ビルドすると、意図せず別関数になっちゃう可能性があるということですね。

 ※エラーは出ません!

 

overrideを書いた場合

 overrideとして紐づける基底クラスの関数を探しに行く模様。

 もし、基底クラスにvirtualの関数がない場合・・・

 ビルドエラーになります。

 

こんなイメージですかね?

 

さて、ビルドするとどうでしょうか?

 

Arduinoで試してみました。↓

 

 

紐づける基底クラスのvirtual関数がないというエラーですね!

 

素敵!

 

 

これ、知ってたら絶対使ってたと思う!

以前、とある方が修正した後、特定の処理の時のみ画面遷移が崩れたことがありました。

 

この時、とある関数に引数を追加したかったらしく、、、

オーバーライドしている関数に引数を追加しちゃったんですよね。

 

その瞬間、別の関数になってしまいます。

 

もちろんビルドエラーなんて出ません。

 

別関数として宣言されて

特定の動作の時は親クラスの関数が呼び出されるようになっちゃったという落ちでした。

 

 

 

 

しかし、なんでこんな都合の良い指定子を知らなかったんだろう。。

 

 

おもむろにHEW起動・・・

 

 

はい、

ビルドエラーです。

 

もしかしてと思い、いろいろ調べてみたんですが、

↓ここのwikiにヒントがありました。

 

 

C++においてもC++11override修飾子が導入されたが、

override修飾子の指定はオプションであり必須ではない。

 

なるほど。

SAIが見たことないわけです。

 

 

とっても勉強になりました!

 

他人のコードを見るのって、勉強になって楽しいね!

 

 

※今回は、Z-2のコードにoverrideを追記しただけなので、サンプルコードはなしです。

 

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

雑談

 

色々調べていると、

そして、同様に関数の後ろに記載する指定子として、

 

 

うーん・・

 

override に final
 

そういえばどこかで見たことがあるような気がしてきました。

 

何だっけ・・・・

 

ほかにSAIがオブジェクト指向で使ったことある言語といえば、

 

 

あっ! Javaだ!

 

Javaは、オーバーライドするためには

@override

がありました!

 

そういえば変数とかも変更されたくないときには

@final

ですね。

 

 

SAIが使っていたのは、

お遊びとテストアプリを作っていた

docomoのiアプリのDoja4.0とか

 

 

Javaで遊んだことがあるという理由だけで

急遽バグ解析+コードチェックやってくれと言われた

android1.6です。悪名高いIS01です。。

世間でボロカスに言われた、

 

その後、android2.0でアプリ作ってくれと言われて、

これ以上、組み込みJavaにかかわりたくないと思った記憶があります。

 

Javaなんてメモリ管理もできないの

ガベージコレクション任せ

 

組み込みには向いていないと思うのです。


懐かしいなぁ・・・

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

 

 

 

 

 

【電子工作C++編】A-2.Arduinoで同じクラスを複数作ってみよう

 

前回は、ArduinoでC++のクラスを作ってみました。

 

前回わかったクラスの利点その1は、

 

生成時にコンストラクタが呼び出される。

終了時(※1)にデストラクタが呼び出される

(※1:前回のパターンでは、関数が終了したタイミングでStackの削除が行われたとき)

 

このことで、変数の初期設定が楽になりますね。

 

と、書きましたが、

同じクラスを一つしか使わないのであれば、あまり意味ないですね。

 

クラスごと移植するのがちょっと便利なくらい。

 

C++の利点はこの程度ではありません。

 

 

今回は、クラスの利点その2です。

 

クラスは構造体のようなものだと話しましたが、

ただの構造体ではありません。

関数ごと、構造体にしているのです。

 

ということは、

クラスを二つ変数定義すれば、関数ごと2つできるイメージなのです。

 

class LedClass
{
 public:
  /* costructor */
  LedClass(int aPort);
  /* destructor */
  ~LedClass();
  /* 出力設定 */
  void SetOutput(bool aOutput);
 private:
  int iPort;
  bool iStatus;
};

↑これが2セット、別変数として扱えるイメージです。

 

例えば、以下のように2つ変数定義すれば、

内部の変数もコピーされているので、

関数を新たに作らなくても

 

  LedClass  LedClass1(StackIoPort1);     // ポート1用のクラス.

  LedClass  LedClass2(StackIoPort2);     // ポート2用のクラス.

 LedClass1.SetOutput(true);     // ポート1を点灯

 LedClass1.SetOutput(true);     // ポート2を点灯

 

 

こうすることで2つのポートを簡単に操作できるようになります。

 

もっというなれば、同じ操作をするなら、

配列にしてしまえば便利ですよね!

 

 /* スタック上にクラスを生成 */

  LedClass  lStackLedClass[3] = { CPort1, CPort2, CPort3 };

  /* 3つを同時に点灯 */
  for(int i=0 ; i < 3;i++)
  {
    lStackLedClass[i].SetOutput(true);
  }
  

配列なので、ぐるぐる回してやればいいです。

また、特定の番号を指定してやれば、1灯だけ制御もできますね。

 

それでは、

3ポートまとめて動作させてみましょう!

 

※コードは最後に書いてますので、試してください。

 

 

ね、クラスって便利でしょ!

SAIでした。

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

雑談

 

クラスって色々な機能があるので、

どの機能から説明するか悩みますね。

 

とっととヒープにインスタンスを生成する、”new”を説明したいものの

その前にヒープ、スタックの概念を理解する必要があります。

 

これを理解しないと、メモリリークしまくりになっちゃいます。

C言語を使う場合、長文や絵を操作しない限り、

なかなかAlloc()を使わないので、”ヒープ”という概念が難しい気がするのですよね。

 

なので、クラスを"new"するという説明のタイミングを考えています。

 

とりあえず、

Arduinoで遊びつつ徐々にクラスを使っていきましょう!

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

本日使ったコードは以下の通りです!

 

宇宙人しっぽ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人あたま

/*
 * @file    CPP_L_A_2_TestCLASS
 * @brief   Lesson A_2 Classを作ってみよう。
 * @author  SAI
 * @date    2021/03/17
 * @note    Classを作ってみよう
 */

/* *** Define 定義 *** */
const int CPort1 = 11;
const int CPort2 = 12;
const int CPort3 = 13;

/*
 * @note    テストクラスのプロトタイプ
 */
class LedClass
{
 public:
  /* costructor */
  LedClass(int aPort);
  /* destructor */
  ~LedClass();
  /* 出力設定 */
  void SetOutput(bool aOutput);
 private:
  int iPort;
  bool iStatus;
};

/*
 * @fn    初期設定
 * @brief コンストラクタ
 * @param aPort LEDを制御するポート番号
 */
LedClass::LedClass(int aPort)
:iPort(aPort),iStatus(false)
{
  /* コンストラクタで指定されたポートを出力設定 */
  pinMode(iPort, OUTPUT);
}
/*
 * @fn    終了設定
 * @brief デストラクタ
 * @note  終了時には必ずリソースを終了状態にする。
 *        生成したヒープ、つないだセッションなど開放する
 */
LedClass::~LedClass()
{
  digitalWrite(iPort, LOW);
}
/*
 * @fn    出力設定
 * @brief 出力の設定を切り替える
 * @param aOutput ON/OFFを設定する true=点灯 false=消灯
 */
void LedClass::SetOutput(bool aOutput)
{
  digitalWrite(iPort, aOutput);
}

/*
 * @note  Arduinoで最初に呼ばれる関数
 */
void setup() 
{
//今回はなし
}

/*
 * @note  ぐるぐるループ
 */
void loop() 
{
  delay(5000);
  /* スタック上にクラスを生成 */
  LedClass  lStackLedClass[3]={CPort1,CPort2,CPort3};

  delay(500);
  /* 3つを同時に点灯 */
  for(int i=0 ; i < 3;i++)
  {
    lStackLedClass[i].SetOutput(true);
  }
  
  delay(500);

  /* 3つを順に消灯 */
  for(int i=0 ; i < 3;i++)
  {
    lStackLedClass[i].SetOutput(false);
    delay(500);
  }
  
  /* 3つを順に点灯 */
  for(int i=0 ; i < 3;i++)
  {
    lStackLedClass[i].SetOutput(true);
    delay(500);
  }
  
  /* 関数終了時にスタックが解放されて、デストラクタが走る
    同時に、デストラクタでLEDを消灯する*/  
}