1

次のコードが期待どおりに機能しないことに少し驚いた。

#include "stdio.h"

class RetA
{
public:
    virtual void PrintMe () { printf ("Return class A\n"); }
};

class A
{
public:
    virtual RetA GetValue () { return RetA (); }
};

class RetB : public RetA
{
public:
    virtual void PrintMe () { printf ("Return class B\n"); }
};

class B : public A
{
public:
    virtual RetA GetValue () { return RetB (); }
};

int main (int argc, char *argv[])
{
    A instance_A;
    B instance_B;
    RetA ret;

    printf ("Test instance A: ");
    ret = instance_A.GetValue ();
    ret.PrintMe (); // Expected result: "Return class A"

    printf ("Test instance B: ");
    ret = instance_B.GetValue ();
    ret.PrintMe (); // Expected result: "Return class B"

    return 0;
}

では、値を返すときに仮想メソッドは機能しませんか?ヒープにリターンクラスを割り当てることに戻す必要がありますか、それともより良い方法がありますか?

(実際には、これを実行して、コンテナークラスから継承するいくつかの異なるクラスが、クラスに応じて異なるイテレータークラスインスタンスを返すようにします...)

4

5 に答える 5

17

ポリモーフィックな動作は値では機能しません。これを機能させるには、ポインターまたは参照を返す必要があります。

値で返すと、「スライス」と呼ばれるものが得られます。これは、オブジェクトの親部分のみが返されることを意味します。したがって、子オブジェクトを親オブジェクトに正常にストライピングしたため、これはまったく安全ではありません。

見てみましょう: オブジェクトスライスとは何ですか?

于 2009-08-10T09:18:49.913 に答える
0

動的オーバーロードを取得します。動的タイプとは異なる静的タイプを使用する必要があります。あなたはここにいません。値の代わりに参照またはポインターを返します(そしてライブ時間に注意を払います)。

于 2009-08-10T09:15:12.043 に答える
0

すでに述べた「スライス」問題に加えて、PrintMeメソッドも仮想である必要があります。

struct B 
{
   void print1() const { std::cout << "B" << std::endl; }
   virtual void print2() const { print1(); }
};
struct D : public B
{
   void print1() const { std::cout << "D" << std::endl; }
   virtual void print2() const { print1(); }
};
B& f() 
{
   static D d;
   return d; // the object returned is in fact a D, not a B
}
int main(){
   f().print1(); // B: calling a non-virtual method from a B reference
   f().print2(); // D: the method is virtual will exec B::print2
}
于 2009-08-10T15:03:10.330 に答える
0

Virtualは、型のポインターまたは参照宣言に適用できるため、コードを変更します:virtual RetA&GetValue()またはvirtual RetA * GetValue()、ただし、virtualについては発行しません。「コピーセマンティック」を使用します。

于 2009-08-10T09:18:22.490 に答える
0

ポインタまたはアドレスを返す必要があります

virtual RetA GetValue () { return RetB (); }

そうでない場合、GetValueから取得するのはRetBではなくRetAです。

于 2009-08-10T09:21:53.387 に答える