質問: new derive; ba.pri(); de.pri(); std::cout << "\n\n"; b->pri(); bb->pri(); d->pri(); _getch(); return 0; } ```
回答: 元質問が編集されて内容が変わっている上、改善待ちも消えたので別回答を追加 正直、適切な教科書を読めば必ず載っている内容で目新しいものはありません。良い教科書を探して購入されることをお勧めします。オイラは持っていませんがそのシリーズの「中級編」でもよいのかもしれません。まあ SO で訊くのも大いにアリですけどね。 A1. コンストラクタの動作には何一つ変化ありません。 デフォルトコンストラクタだろうが非自明コンストラクタだろうが、コンストラクタ関数の呼び出される順序は 基底クラスのコンストラクタ→自クラスのメンバのコンストラクタ→自クラスのコンストラクタの自作記述部(を再帰的にたどる) `virtual` でコンストラクタを上書きや再定義することはできません(意味ないため) A3. 継承・派生機構を使って、派生クラスのインスタンスを基底クラスへのポインタないしは参照で保持している場合に話を限定します(そうでない=派生クラスのインスタンスを当該クラスへのポインタで扱う場合には下記考慮は不要) そういう場合 [c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") では適切なデストラクタを起動するためには一工夫が必要です(他の言語ではこの手の工夫をしなくてよいものもあります)。 工夫とはデストラクタに `virtual` をつけるだけです。逆に言うと「デストラクタに `virtual` がついていないクラスは、その作者がこのクラスを派生させるなと意思表明している」と読むことができます。 サンプル: ``` struct a { ~a() { std::cout << "a::~a()\n"; } }; struct b : a { ~b() { std::cout << "b::~b()\n"; } }; struct c : b { ~c() { std::cout << "c::~c()\n"; } }; ``` たとえば ``` int main() { b obj; } ``` の挙動と ``` int main() { a* p=new b(); delete p; } ``` の挙動を比較してみてください。そののち、上記例を `virtual ~a() { ... }` に修正して更に試してみるとよいかもしれません。 A2. まったく違います。で、両方とも間違っているんだと思います。 別回答で書いたとおり、クラスライブラリが提供している基底クラスに対してオイラたちクラスライブラリのユーザーが派生クラスを作る=抽象的な何かに具体的機能を追加する、ってことです。オイラたちはその必要があるから具体的機能を追加したわけで、当然自分の書いているプログラムの中からはその具体的機能を使いたいってことです。以下そういう状況に話を限定。 `base* p=new base();` の意味は機能追加前のクラスを使うってことなので、ほぼまったく無意味(クラスライブラリを派生させた意味がない) `base* p=new derived();` の意味は機能を追加したクラスのインスタンスを作るが、その追加機能を使うすべが無いってことでこれもほぼ無意味 `derived* p=new derived();` であれば、追加機能があるインスタンスを作って、その追加機能を `p` 経由で呼ぶことができる、ってことなので意味があるわけです。この状況なら、クラスライブラリ側が用意している関数 `extern int DoModal(base*);` を `DoModal(p)` のように呼び出すことができます(説明のために非メンバ関数としておく)。ここで `derived*` → `base*` の暗黙変換がなされています。 原則論として、派生→基底のポインタ変換は作者が違う「境界層」で使うこととなります。数ヶ月前の自分は他人ですからそういう場合にも使うことがあるでしょうね。 SO/SE 的には発言1スレッドに付き質問1回答1が望ましいとされているようなので、次からはぜひそうしてください。