蒼いホッチキス
Amebaでブログを始めよう!

50日目、ポリモーフィズムと配列

プログラムな話。

昨日、C++のコードを書いてた時に遭遇したエラーを書いておく。

例えば


class A{
public:
  A() : a( 1 ){}
  virtual int get(){ return a; }

private:
  int a;
};

class B{
public:
  B() : b( 2 ){}
  int get(){ return b; }

private:
  int b;
};

int main()
{
  A* p = 0;
  p = new B;

  count << p->get() << endl;  // 出力は 2 となる、はず

  delete p;
  return 0;
}



これはまあいいおk。
形としてはメンバ変数を持つ具象Bが抽象を持ったAを継承する典型的なポリモーフィズム。

問題は以下にて発生する。
変化するのはクラス自体ではなく、main関数。



int main()
{
  A* p = new B[ 10 ];

  for( int i = 0; i < 10; ++i ){
    cout << p[ i ]->get() << endl;
  }

  delete [] p;
  return 0;
}



個人的にはここで2が縦に並ぶ感じで行ってほしいところだがこれにはうまくいかない場合があり
アクセスエラーとかが起きるかもしれない。ちなみに自分の場合は2つめの配列のgetメソッドにアクセスした際にエラーが発生した。
内容をみると、仮想関数テーブルに何も入ってなかった。

なぜこんなエラーが発生するか。
Bにメンバ変数があるがためにAとBのサイズが異なる。
つまりAの( p + 1 )とBの( p + 1 )が違うのでここで差が発生してちゃんとした場所にアクセスしてくれなくなってしまうのだ。

ちなみにこれ、試しに上のプログラムでやってみたらすんなり表示できてしまった。
Bのメンバ変数を配列にして大きくしたらうまく?エラーが起きた。

といっても最初の組んでいた時のプログラムでもfloatを1つ増やしただけだったし
少なくともこれはやってはいけないかき方という書き方だ。
エラーが起きなくてもそれは運が良かったと考えた方が自然。
(むしろ危険が眠る事になるのでアンラッキーかも)


結論として、ポリモーフィズムと配列は混ぜちゃいけません!


絶対これいままで1回は組んでたと思うんだよな……
今回のことでむしろ今後の危険性を排除できたわけだからよかったと思う。

45日目、寝る

蒼いホッチキス

完璧な3日坊主だった。
いや、4日目も更新しようとしたけど、もう日またいじゃってたしじゃあもういっか、みたいな。
気付けばもう5月中ば過ぎてるよ……

さて45-3で42日の間があいてその間にGWがあったり、帰って友人と酒を飲んだり
その帰りに絵師100人展など行ってた。

帰りは一緒にこっち側にくる友人がいたので一緒に来たけど、絵師100人展、入場料1000円高いよな……いや行くけどさっていう話をしてて行ってみたら思った以上の充実感。

おかげで写真の図録(2500円)やクリアポスター(1000円)など買っちゃったり。
当初の予定じゃこんなはずじゃなかった……orz

やっぱ絵がかけるっていうのはいいよね。
個人的野望としてはいつか同人ゲームとか出してみたいよなぁとか(技術的壁は置いといて)思ってるけどやっぱりそこで出てくる問題はグラフィック面だったり。
絵がかけるってだけで夢が広がリング。

そんなことを思いながら見てたり、見ていなかったり。
知ってる絵師さんとかやっぱテンション上がるよね、うん。

絵描ける人ってどうやって絵をかけるようになったんだろ、やっぱ毎日描いてるのかなぁ。
絵はへたってわけじゃないけどうまくないっていうか、手とか書けない。
なんなんだろうな、あれ。なんでみんなスって書くことできるんだろう、不思議だ。


なんか久々に書いてたら4時回ってる。早く寝よう。今日遅刻しちゃったし(´・ω・`)

最近、家じゃプログラミング触ってないや。
プログラムは打たないと力が付かないからやんなきゃなんだけど、休みの日は基本寝てるからなぁ。

おやすみなさい。

3日目、名刺入れ

蒼いホッチキス


昨日、ほしい名刺入れがあるお店が夜7時にはしまっていたがために買えなかったので
今日改めて買いに。

Qurli(クルリ)というなかなか名刺入れとしては変わった感じ(なのかな?)で購入。
入ってる名刺を指でスライドさせることでスマートに取り出すことができる。

上の方から差し込んで、中ではバネで名刺を止めてるのだけれど、サンプルとして置いてあった
ものは普通にはさめたけど、手元のはバネが弱いんだろうか、1枚じゃ挟めなくて上から落ちてきちゃう。

名刺はそれなりに入れるので普段は特に影響ないけどちょっと残念だった。



さて、プログラミングの話だけれども結局昨日はポップアップ開いて閉じて、新たにまたウィンドウを
開くということをして、Kinect( openNI )に関しては一切やらずに眠くて寝てしまった

で、やってて思ったのだけれど今まで自分はメッセージプロシージャにて
エスケープキー押された時はPostQuitMessage( 0 )で終わらせてたんだけど
(学校のサンプルソースがそうだったので)
これだとWM_CLOSEいかなくてDestroyWindowが実行されてないんじゃないかと思った。

ゲームプログラムの場合、メインループは常に回しているので
while( msg.message != WM_QUIT )
って感じでその中でPeekMessageをよんでたけど、PostQuitMessage( 0 )はWM_QUITを宣言するので
そうするとそのまま終わっちゃうんですよね……

自分の思ってる通りとすれば、ウィンドウ自体がゾンビ状態になるような気がするんだけど
実際のところはいったいどうなんだろ……いままで特に変な感じしてなかったからもしかしたら
大丈夫じゃないかと思ってしまったり。

なんだかそこらへんがよくわかってない……

自分の中で思ってる流れは
普通「×」が押されれば、DefWindowProcからWM_CLOSEでそこでDestroyWindow→WM_DESTROYで
そこでPostQuitMessage(0)でエンドって感じだと思う、そうするとやっぱダメだよな。

つまりそもそもPostQuitMessage自体、WM_DESTROY内でしか呼んじゃダメってことか。
(調べてるときに、そんな事がどこかのサイトに書いてあった)

とりあえずそこらへんがなんかイヤな感じなので、現在はエスケープおされたらWM_CLOSEを
呼んでやるということで、自分の中で落ち着く感じになった。それかDestoryWindowを呼んでやるとか。

これきっと基本中の基本なんだろうな……
普段、メッセージプロシージャとか触らないから気付かなかった