2011-11-26 8 views
7

これは少し驚きましたが、私はいくつかのコードで遊んでいましたが、関数が親クラスを参照で受け取り、子インスタンスを渡すと、少なくとも私のコンピュータでは、発生しません。説明する:参照渡しは常にスライスの問題を回避しますか?

#include <iostream> 

class Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Parent::DoSomething" << endl; 
    } 
}; 

class Child : public Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Child::DoSomething" << endl; 
    } 
}; 

void performSomething(Parent& parent) 
{ 
    parent.doSomething(); 
} 

int main(int argc, char** argv) 
{ 
    Child myChild; 

    performSomething(myChild); 

    return 0; 
} 

これはChild::DoSomethingを印刷します。

私が言ったように、私は少し驚いた。私は、参照渡しはのようにであることを知っています(私の理解ではもっと安全ですが)。しかし、そうする際に多形性を保つことはまだありません。

私はちょうど確かめたいのですが、これは起こるはずですか、それとも "自分のマシンで動作する"タイプのインスタンスですか?

+0

これは「スライシング」とは異なります。また、そのコードはコンパイルされますか? 'std;を使っているのは何ですか? –

+0

これは 'using namespace std'です。私は、私はポイントを得ることができたと思ったが、サイト全体の利益のためにコードを整理した。 – Anthony

答えて

9

表示される動作は正しいです。これはどのように動作するはずです。参照はポインタのように機能します。

+0

ありがとう、それは私が考えたものです。私が言及したように、私は正当性チェックを望んでいたので、私は間違った前提をしなかった。 – Anthony

2

はい、参照にバインドすると動的バインディングが有効になります。これは、オブジェクトの動的型と静的型の違いによって発生します。

パラメータを値で指定すると、Parentクラスになります。参照またはポインタを介して何かを渡して仮想関数を呼び出すと、実行時に参照されている実際のオブジェクトのdynamic typeまたはmost-derived typeが検索されます。

3

これは起こりそうです。参照渡しは、ポインタを渡すのとまったく同じです。これは、同じことをフードの下で行います。これには魔法はありません。多相オブジェクトの各インスタンスは、それに関連する仮想関数テーブルを有する。あなたが何かをコピーしない限り、あなたはその情報を失うことはありませんし、あなたの仮想関数呼び出しは期待どおりに動作します。

値渡し時に問題が発生する理由は、関数シグネチャで指定したタイプのコピーコンストラクタを使用するため、スーパークラスのまったく新しいインスタンスになります。

11

「スライシング」とは、基本コピーコンストラクタが派生クラスから正確なタイプの一致を区別できないことを指します。スライシングを呼び出す唯一の方法は、基本コピーコンストラクタを呼び出すことです。値で引数を渡す場合、通常、これは他の状況を図ることができても、発生しますが、決してそのようなことをやっていないしている

class Base { }; 
class Derived : public Base { }; 

void foo(Base); 

int main() 
{ 
    Derived x; 

    Base y = x; // flagrant slicing 
    foo(x);  // slicing by passing by value 
} 

、あなたが任意のスライスの状況に遭遇しないように。

+2

渡すときにコピーコンストラクタを記述すると、この回答が完璧なものになります。 – dani