キャストをミスったときのエラー

初心者丸出しの記事を書くよー

#include <iostream>
#include <cstdio>

using namespace std;

class Man{
	public:
		int height;
		int weight;
	public:
		Man(int h_, int w_):height(h_),
		weight(w_){
		}
		string toString(){
			char temp[100];
			sprintf(temp, "Man<h=%d, w=%d>", height, weight);
			return string(temp);
		}
};

class Fighter: public Man{
	protected:
		int strength;
	public:
		Fighter(int h_, int w_, int s_):Man(h_, w_),
		strength(s_)
		{
		}
		string toString(){
			char temp[100];
			sprintf(temp, "Fighter<h=%d, w=%d, s=%d>", height, weight, strength);
			return string(temp);
		}
};


int main(){
	Man a = Man(160, 50);
	cout << a.toString() << endl;
	Fighter b = Fighter(180, 90, 100);
	cout << b.toString() << endl;
	/* pointer */
	cout << "*pointer test" << endl;
	Man* p = &b;
	cout << p->toString() << endl;
	cout << ((Fighter*)p)->toString() << endl;
	/* reference */
	cout << "*reference" << endl;
	Man& r = b;
	cout << r.toString() << endl;
	cout << ((Fighter&)r).toString() << endl;
	/* copy */
	cout << "*copy" << endl;
	Man m = b;
	cout << m.toString() << endl;
	cout << ((Fighter)m).toString() << endl; /* 56行目。エラー起こるよ! */
	return 0;
}

オブジェクト・スライシングの実験をしてたんだけど、この56行目でこんなエラーが出ます。(gccのg++の3を使ってます。)

slicing.cpp: In function `int main()':
slicing.cpp:56: error: no matching function for call to `Fighter::Fighter(Man&)'

slicing.cpp:21: note: candidates are: Fighter::Fighter(const Fighter&)
slicing.cpp:25: note:                 Fighter::Fighter(int, int, int)

そういえば、無効なキャスト*1をしたときに「キャストできないよ!」って言ってくれればいいのに、なんで「コンストラクタが無いぞっ!」とかかわいく言ってくるのかなーと疑問に思っていたのですが、そういえば以前詳説C++*2の、演算子オーバーロードのあたりで、キャスト演算子の話のときにそんな話が出たので復習してみた。

どうも、「型変換コンストラクタ」とか言うらしい。これは、1つの引数で呼べるコンストラクのことだそうで、例えばそのコンストラクタの1つの引数がX型で、コンストラクタを定義しているクラスがTなら、暗黙、明示どちらでもX→Tの変換ができるらしい。というわけでやってみた。

#include <iostream>
#include <cstdio>

using namespace std;

class Man{
	public:
		int height;
		int weight;
	public:
		Man(int h_, int w_):height(h_),
		weight(w_){
		}
		string toString(){
			char temp[100];
			sprintf(temp, "Man<h=%d, w=%d>", height, weight);
			return string(temp);
		}
};

class Fighter: public Man{
	protected:
		int strength;
	public:
		Fighter(int h_, int w_, int s_):Man(h_, w_),
		strength(s_)
		{
		}
		Fighter(Man& m_):Man(m_.height, m_.weight){
			strength = 0;
		}
		string toString(){
			char temp[100];
			sprintf(temp, "Fighter<h=%d, w=%d, s=%d>", height, weight, strength);
			return string(temp);
		}
};


int main(){
	Man a = Man(160, 50);
	cout << a.toString() << endl;
	Fighter b = Fighter(180, 90, 100);
	cout << b.toString() << endl;
	/* pointer */
	cout << "*pointer test" << endl;
	Man* p = &b;
	cout << p->toString() << endl;
	cout << ((Fighter*)p)->toString() << endl;
	/* reference */
	cout << "*reference" << endl;
	Man& r = b;
	cout << r.toString() << endl;
	cout << ((Fighter&)r).toString() << endl;
	/* copy */
	cout << "*copy" << endl;
	Man m = b;
	cout << m.toString() << endl;
	cout << ((Fighter)m).toString() << endl; /* エラー起こらないよ!でもstrengthは0だよ!Fighter涙目! */
	return 0;
}

実験終わり。夏休みも終わり。

*1:今回の場合は、基底型→派生型の変換。派生型にあって基底型に無いメンバをどうしていいかわからなくなるとか何とか。

*2:足跡45の愛?読書。もう一年ぐらいちびちび読んでる。頭のほう忘れた。あといつのまにか絶版になってた。