4

私は C++ V1 で C++ form Thinking を勉強しています。継承を示す例に出くわしました。ここに行きます

#include <iostream>

class Instrument{
public:
    virtual void play(){
        std::cout<<"instrument::play()";
    }
};

class Wind: public Instrument{
public:
    void play(){
        std::cout<<"Wind::play()";
    }
};

void tune(Instrument& i){
    i.play();
}
int _tmain(int argc, _TCHAR* argv[])
{
    Wind flute;
    tune(flute);
    return 0;
}

Wind::play()これはコンソールに出力されます。

しかし、メソッド「tune」を次のように変更すると

void tune(Instrument i){
    i.play();
}

出力はinstrument::play()

コピーではなくフルートの参照が渡されるように「&」が追加されているため、なぜプログラムは ?instrument::play()の代わりに出力するのWind::play()ですか?

4

5 に答える 5

17

渡されるコピーには typeInstrumentではなく typeWindがあるためInstrument、関数が取る型は です。これは「スライス」として知られています。

于 2013-10-09T18:04:40.443 に答える
7

C++ でのオブジェクト式のポリモーフィックな動作は、動的な型によって決まります。

  • type の参照を typeのオブジェクトにアタッチすると、 によって参照されるオブジェクトの動的な型が維持されます。つまり、 typeで宣言されていても、実際には type の実際のオブジェクトを参照しています。そして、それがとして動作し続ける理由です。オブジェクトをポインタで参照する場合も同様です。Instrument &iWindiiInstrumentWindiWind

    形式的に言えば、式の静的型iですがInstrument、同じ式なら動的型Windという意味です。このため、iは としてポリモーフィックに動作しWindます。

  • 一方、type の値を持つオブジェクトを割り当てる(または初期化する) と、 typeの独立したスタンドアロン オブジェクトが作成されます。このオブジェクトのタイプは です。そのため、スタンドアロン コピーはすべてのポリモーフィック コンテキストと同じように動作します。Instrument iWindiInstrumentInstrumentiInstrument

    繰り返しますが、形式的な言葉で言えば、この場合、式の静的型動的型の両方が であることを意味しiますInstrument。このため、iは としてポリモーフィックに動作しInstrumentます。

C++ 言語では、オブジェクトの動的な型を「保持」する唯一の方法は、ポインターまたは参照を使用してそのオブジェクトを参照することです。ここでのキーワードは「参照」です。新しいオブジェクトを作成するのではなく、 既存のオブジェクトを参照します。そして、これらの既存のオブジェクトは、ネイティブ タイプに従って引き続き動作します。type のオブジェクトは、Wind引き続き type のオブジェクトとして動作しますWind(これは、仮想関数呼び出しの解決方法など、ポリモーフィックな動作にのみ適用されることに注意してください。)

ただし、(オリジナルを参照するのではなく) オブジェクトの独立したコピーを作成すると、そのコピーは、独自の型と関連するプロパティを持つ独自の生命を獲得します。タイプのスタンドアロン コピーは、元のオブジェクトとは関係ありません。オブジェクトのコピーとして生まれたという記憶はありません。として動作します。InstrumentWindWindInstrument

于 2013-10-09T18:12:01.633 に答える
3

これが「スライス」と呼ばれる問題です。にコピーWindすると、InstrumentになりますInstrument

于 2013-10-09T18:04:56.617 に答える
0

void tune(Instrument i){
    i.play();
}

Instrumentオブジェクトの場合は新しいインスタンスを作成し、Instrumentオブジェクトが印刷されますinstrument::play

参照演算子を使用したとき&に、型の既存のオブジェクトを参照しましたWind

于 2013-10-09T18:08:15.143 に答える
-2

関数が呼び出される理由は、オブジェクトをスライスInstrument::playするため、コピーを渡すと、実際にはInstrument渡すオブジェクトの一部だからです。

于 2013-10-09T18:04:31.087 に答える