【C++で3Dゲーム】3.コンストラクタの後ろのコロン(初期化)
投稿日:2024-03-27
最終更新日:2024-03-30
環境
はじめに

まずは以下のソースコードをご覧ください。

引数なしのコンストラクタを定義しているのかと思いきや、1行目の後ろに「:num(5), fl(2.0f)」というよくわからないものが付いています。

私は最初に見た時に「放っておいても動くけど、ナニコレ?」ってなりました。

本記事では、コンストラクタの後ろについた謎のコロンについて解説します。

また、初心者がクラスのデータメンバ(メンバ変数)を初期化する時に書きがちなコードとの差も2つ紹介します。

タイトルからは反れますが、「2.0f」についても最後に補足があります。ひとまず2だと思ってください。

この記事は「ゲームプログラミング C++」(2018, Sanjay Madhav 著, 吉川 邦夫 訳, 今給黎 隆 監修)のChapter1に関連します。

本日使うソースコード

example.cppの実行結果は次のようになります。

解説

上記のサンプルコードの実行結果を見ればお分かりいただけるように、コロン以降でデータメンバ(メンバ変数)の初期化をしています。

C++では、コンストラクタの後ろに「:変数名(値)」と書くことで、そのデータメンバを指定した値で初期化できます。

初期化するのであれば、コロンを使わずにコンストラクタを次のように書いても良いのではないか、と思う人もいると思います。私のことです。(新しく別のソリューションを作って、その中でexample2.cppとします。ヘッダファイルは同じです。)

確かに実行結果として同じ画面を得られます。(下図)

しかし、コロンを使った初期化の方が、一般に優れていると言われています。以降でその違いを2つ紹介します。

違いその1

インスタンス生成時にデータメンバを保存する領域を確保しますが、コロンを使った初期化では、その時に同時に値を代入してくれます。

一方でコロンを使わない場合は、一度データメンバを保存する領域を確保し、その後に代入文を実行することで初期化を実現しています。

一見同じように見えますが、実は違いがあります。

どのぐらいの差かはわかりませんが、コロンを使った初期化の方が実行速度が速くなるらしいです。

「領域確保→代入」と「領域確保→次の命令文確認→代入文実行」という違いがあることを考えると、ステップ数が少ない方速くなるというのは納得できる…気がします

ゲームではインスタンスを大量に生成することがあるので、もし本当なら結構恩恵が大きいと思います。

現状では違いがあるのか確証が持てませんが、もう一つ大きな違いがあります。

違いその2

ヘッダファイルで、flにconst修飾子を付けて宣言してみましょう。(const float fl;という風に変更)

example.cppは実行できますが、example2.cppは実行できません

コロンを使った初期化では、領域確保と代入がセットなので、定数であってもこの時のみ「代入」(値の設定)が可能です。

「定数に代入」なんて混乱させるようなことを言わないでくれという言葉が聞こえてきそうですが…

クラスやコンストラクタ関係なく、通常の定数宣言時に(あたかも定数に「代入」しているかのように)「const float pi=3.14;」と書いて初期化することを思い出してください。すなわち、領域確保時であれば定数に値を設定することが可能ということです。

しかしコロンを使わない初期化では、領域確保と代入文実行が別々の処理なので、領域確保後にflが定数として値が固定されてしまって、代入文が実行できなくなってしまいます。したがって、example2.cppはエラーになります。

このような差を見ると、データメンバの初期化に関しては、コロンを使った初期化が厳密に初期化と言えて、コロンを使っていない方はあくまで初期化っぽいことをしているに過ぎないと解釈できます。

実行できる、できないという差が出てくると二つの初期化方法に違いがあることを実感できるかと思います。

supplement
「2.0fって何?」と思う人のために
後ろに「f」をつけると、この2.0はfloat型だということを明示できます。
勝手にdouble型など別の型の小数として処理されてしまうことを防ぐためにつけることがあります。