• 締切済み

継承でのエラーについて

現在C++を勉強しているのですが、教えてください。 サブクラス作成時のエラーなのです。 長いですがソース見てください。 勝手にインデントが無くなるので見にくいですが…。 #include <iostream> #include <string> using namespace std; class Hito{ private: string Name; public: Hito(string); //コンストラクタ void SelfIntro(); //自己紹介する }; //Hitoのコンストラクタ Hito::Hito(string str){ Name = str; } //自己紹介するメソッド void Hito::SelfIntro(){ cout << "私は、" << Name << " です。" << endl; } class Syusyo: public Hito{ private: int Ninki; public: Syusyo(string,int); void SayNinki(); }; //Syusyoのコンストラクタ Syusyo::Syusyo(string str, int year){ Hito(str); Ninki = year; } void Syusyo::SayNinki(){ cout << "私の任期は" << Ninki << "年です。" << endl; } int main(){ string str = "小泉アホの助"; int year = 5; Syusyo hito1(str,year); hito1.SelfIntro(); hito1.SayNinki(); return 0; } HitoクラスからSyusyoクラスを作っています。 そのSyusyoクラスのコンストラクタでエラーが出るのです。 内容は、 「デフォルトコンストラクタがありません。」 と言うものです。 参考書通りに Syusyo::Syusyo(string str, int year):Hito(str),Ninki(year){} とすればエラーにはなりません。 なぜ前出の文だとエラーになり、後出の文は大丈夫なのでしょうか? 文の表現が違うだけだと思うのですが…。

みんなの回答

回答No.5

C++では、断りがない限り、派生クラスのコンストラクタは、自分自身を実行する*前*に、基底クラスの、デフォルトコンストラクタを呼び出します。 これは、「引数のない」コンストラクタのことです。 ですから、この場合は、 Hito::Hito() というコンストラクタが必要です。 たとえば、 Hito::Hito() { name = ""; } があれば、 //Syusyoのコンストラクタ Syusyo::Syusyo(string str, int year){ name = str; Ninki = year; } は可能です。 ※つまり、名前無しで生成したインスタンスは無名にする。というのあれば、後で名前をつけることができる。 さらに、 Syusyo::Syusyo() の中で、 Hito(str); というのは、やめた方がいいでしょう。 これは、この場所で、(既に Hito クラスとしては構築が終わっているので)Hito() を構築できないためです。 今回の場合、Hito() クラスには、string を引数とするコンストラクタしかないために、基底クラスの構築のために、Hito() クラスに string を(Syusho クラスの構築に入る前に)渡す必要があるのです。 あと、メンバ変数に対しても、 Ninki(year) とするのと、コンストラクタの中で、 Niki = year; とするのは、少し違います。 前者は、初期化 後者は、代入です。調べてみるとおもしろいと思います。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.4

> 文の表現が違うだけだと思うのですが…。 処理内容の表現ではなく、文法上の構文が違います。 > 参考書通りに書けばエラーにならないのは分かっていますが、 > 「…:Hito(str)…」のように ":" を使いたくないのです。 ":"を使うのが、C++の初期化の文法です。 プログラミング言語の場合、文法に違反したソースはエラーになるのが普通です。 言語の文法に従いたくない理由は、なぜですか。 コンパイルを成功させたくないということですか。 > ":"を使わないで基底クラスのコンストラクタを実行させることは出来ないのでしょうか? 無理でしょう。 "自分のインスタンスの"基底クラスのコンストラクタを呼ぶのは、":"を使った文法になります。 それ以外の手順は…ハックですね。(むりやりdefineから別の手段まで 基底クラスのprivate以外のメンバ関数を呼び出すことはできますので、 setterを基底クラスに用意すればstrの代入はできますが、 初期化での自分のインスタンスに対する基底クラスのコンストラクタ呼び出しはできません。(初期化と代入は別のものです) # 十中八九意図と違うでしょうが、他のインスタンスであれば、 # コンストラクタの中で、基底クラスの変数を作るだけで # "基底クラスのコンストラクタが実行"されます。ただの言葉遊びですが。

回答No.3

> ":"を使わないで基底クラスのコンストラクタを実行させることは出来ないのでしょうか? おそらく無理。

回答No.2

> 文の表現が違うだけだと思うのですが…。 意味も変わります。 コンストラクタの { が始まるまでに、 基底クラスのコンストラクトは完了しています。

onara-pu-
質問者

お礼

回答ありがとうございます。 だいたいエラーになる理由は分かったのですが、どのように書けばエラーにならないのでしょうか? 参考書通りに書けばエラーにならないのは分かっていますが、「…:Hito(str)…」のように ":" を使いたくないのです。 ":"を使わないで基底クラスのコンストラクタを実行させることは出来ないのでしょうか?

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

コンストラクタを関数として呼び出したのでは駄目です。 > Syusyo::Syusyo(string str, int year){ > Hito(str); > Ninki = year; > } は < Syusyo::Syusyo(string str, int year):Hito(),Ninki(){ < Hito(str); < Ninki = year; < } と同じです。

onara-pu-
質問者

お礼

なるほど、確かにコンストラクタを関数として呼び出している文と同じですね。 こういう形にすればダメって事ですね。 回答ありがとうございます。

関連するQ&A