3

以下は私のコードです、

#include<iostream>
#include<string>

using namespace std;

class TestClass
{
  public:
    virtual void test(string st1, string st2);

};

class ExtendedTest: public TestClass
{
  public:
    virtual void test(string st1, string st2);
};

void TestClass::test(string st1, string st2="st2")
{
     cout << st1 << endl;
     cout << st2 << endl;
}

void ExtendedTest::test(string st1, string st2="st2")
{
     cout << "Extended: " << st1 << endl;
     cout << "Extended: " << st2 << endl;
}

void pass(TestClass t)
{
    t.test("abc","def");
}


int main()
{
   ExtendedTest et;
   pass(et);
   return 0;
}

コードを実行すると、基本クラスのメソッド('test')が呼び出されます。しかし、メソッドを仮想関数として指定したので、子のメソッドが呼び出されることを期待しています。

では、どうすれば子クラスのメソッドを呼び出すことができますか? ありがとうございました。

4

3 に答える 3

3
void pass(TestClass t)
{
    t.test("abc","def");
}

これを行うと、渡すオブジェクトが にスライスされ、TestClassそのアイデンティティが失われるため、 のように動作し、それTestClassに応じてメソッドを呼び出します。

これを修正するにtは、@Nick が提案したように参照渡しするか、(推奨されません) ポインターで渡します。test仮想とマークされている限り、ID を保持し、適切な関数を呼び出すようになりました。

編集:スプライシングを修正->スライス..バイオショックが多すぎる..

于 2012-12-17T02:24:18.430 に答える
2

参照(またはポインタ)のパラメータを変更する必要があります

void pass(TestClass &t)

このように、元のオブジェクトが使用されます。

于 2012-12-17T02:23:18.867 に答える
1

前述のとおり、これは「スライス」の結果です。何が起こるかの具体的な詳細は次のとおりです。

引数が値渡しの場合、引数のコピーが関数に渡されます。これが発生すると、copy-constructor を呼び出して新しいオブジェクトが構築されます。

あなたの例では、コピーコンストラクターには次のような署名があります。

TestClass::TestClass(const TestClass&);

したがって、実際に何が起こるかは次のようなものです (これもあなたの例です):

ExtendedTest et();
pass(et);
{ // entering scope of pass function ...
  TestClass t = TestClass(t_orig); // inserted by the compiler
  // evaluation of pass function ...
  // ...
} // leaving scope of pass function, t is destroyed.

明らかに、変数 t は TestClass としてインスタンス化されるため、メンバー関数の呼び出しは (ExtendedTest ではなく) TestClass から行われます。

最後に、継承を使用する場合は常に仮想デストラクタを宣言する必要があります。これにより、オブジェクトが破棄されたときのスライスが回避されます。

于 2012-12-17T05:27:16.967 に答える