2010年10月8日金曜日

C++ インスタンス作成時、呼び出されるコンストラクの奇々怪々


さっそくだが、以下の短いC++のコードを見てもらおう

func関数内で、Hogeクラスのインスタンスを作るだけのコードである。
(1)~(4)のそれぞれは、(a)、(b)どちらのコンストラクタが呼ばれるか分かるだろうか。


#include <iostream>

int aaa=5;

class Hoge
{
  public:
  Hoge() {        // (a)
    std::cout<<"constructor 1"<<std::endl;
  };
  Hoge(int bbb) { //(b)
    std::cout<<"constructor 2"<<std::endl;
  };
};


void func(int ccc)
{
  Hoge();    // (1)
  Hoge(5);   // (2)
  Hoge(aaa); // (3)
  Hoge(ccc); // (4)
}


int main() {
  func(5);
  return 0;
}




【回答】
◆ (1)は(a)である。説明不要でいいだろう。


◆ (2)は(b)である。これも説明はいらないだろう。


◆ (3)は(a)である!!
引数のないコンストラクタが呼ばれるのだ。

なぜか。

例えば次の場合、
int(5) は5のint型へのキャストである。曖昧性はない。

int(a) はaのint型へのキャスト、もしくは、
int型の変数aの宣言ともとれる。

このような曖昧性がある場合は、宣言と見なすのがC++の仕様である。

(3)に戻ろう。
Hoge(aaa)は、
aaa変数がキャストされているのか、
Hoge型の変数aaaの宣言か分からない。
しかし、仕様により後者を優先する。
Hoge(aaa) ⇒ Hoge aaa

どうしても引数aaaを使いたければ、
Hoge(hoge)(aaa) とすればよい。
もちろん Hoge hoge(aa) でもよい。


さて、
◆ (4) はどうか。
実は、コンパイルエラーになる。
エラーメッセージ:"declaration of 'ccc' shadows a parameter"

cccの宣言(declaration of 'ccc')が、引数(a parameter)を隠してしまう(shadows)からである。