2012-03-29 3 views
2

なぜオーバーライドは実行時に解決されますが、オーバーロードはコンパイル時に解決されますか?
は、コンパイル時にオーバーライドが解決される理由があります。C++オーバーロードとオーバーライドの解決時間

+0

コンパイル時にどのようにオーバーライドが解決されるか教えてください。 – ildjarn

+0

@ildjarn:私の答えのコメントの中のリンクをチェックしたいかもしれません。 –

+0

@Als:ダイナミック多型が完全に_disabled_(したがって質問/会話とは無関係)のコンテキストは、私が求めていたものではありません。明らかに、多型を使用するためには、多型コンテキスト内にある必要があります。 – ildjarn

答えて

3

コンパイル時にオーバーライドが解決される理由はありますか。期待どおり多型の話をしていると仮定すると、

は、すなわち

#include <iostream> 

class Base 
{ 
public: 
    virtual void Foo() 
    { 
     std::cout << "Base::Foo()" << std::endl; 
    } 
}; 

class Derived : public Base 
{ 
public: 
    virtual void Foo() 
    { 
     std::cout << "Derived::Foo()" << std::endl; 
    } 
}; 

上記のコードが動作するように、このようなことを可能にする:

void CallFoo(Base& b) 
{ 
    b.Foo(); 
} 

int main() 
{ 
    Base b; 
    Derived d; 
    CallFoo(b); // calls Base::Foo() 
    CallFoo(d); // Calls Derived::Foo(); 
} 

CallFoo()は何も知らないことを認識することが重要ですBaseインスタンスまたはDerivedインスタンスを指している可能性があります。すべてCallFoo() getsはBaseへの参照です。実際に何が参照されているかについては何も言わないので、コンパイラがコンパイル時にどのように解釈できるかはわかりません。CallFoo()したがって、Base::Foo()またはDerived::Foo()を呼び出す必要があるかどうかを判断することは、実行時の決定である必要があります。

virtualキーワードを削除すると(オーバーライドを無効にする)上記のコードでBase::Foo()が2回表示され、Base::Foo()ではなくDerived::Foo()ではありません。これは、virtualキーワードがないと、コンパイラはコンパイル時にBase::Foo()への呼び出しを解決するためです。

コンパイラは、実際にはbのタイプを把握するためにできるだけオーバーフローが発生します(つまり、呼び出す必要のある適切な関数は実行時の決定であるため) 。その場合、コンパイル時の決定になります。しかし、それは実装の詳細です。

2

オーバーライドは、仮想関数の実行時に解決されるのは、dynamic bindingが達成されるためです。非仮想関数呼び出しは、コンパイル時に解決されます。

2

なぜオーバーライドは実行時に解決されますが、オーバーロードはコンパイル時に解決されますか?

実際はそれに依存します。
通常、オーバーライドの場合、コンパイラは実行時まで呼び出される実際の関数を特定できません。これは、実行時までBaseクラスポインタが認識されない実際のオブジェクトが存在するためです。このような場合、コンパイラにはオプションがありませんが、実際の関数呼び出しは実行時に解決されます。
しかし、時にはコンパイラはオーバーライドの際にも呼び出す必要がある関数を賢明に&検出できます。そのようなシナリオではコンパイル時に呼び出される関数を解決できます。

オーバーロードの場合、呼び出される実際の関数は、関数に渡されるパラメータだけに基づいてコンパイラによって決定されるため、コンパイラは実行時まで実行を待つ必要はありません。 C++は静的型言語であるため、コンパイル時にはすべての型を知っておく必要があります。

+0

'オーバーライドした場合でもコンパイラが呼び出す必要のある関数をスマートに&決定的に検出することがありますこの例がありますか? –

+0

@Jesse:チェックアウト:[コンパイラはいつ静的に呼び出しを仮想関数にバインドできますか?](http://stackoverflow.com/questions/7291596/when-can-the-compiler-statically-bind-a-call仮想関数)、そして、私が引用したものは、実証済みの事実です。ここに推測はありません。 –

+1

リンクありがとう! –

0

C++での関数のオーバーロードは、コンパイラ自体で処理できます。関数のオーバーロード中、コンパイラは技術的にはname manglingと呼ばれる関数名を「装飾」します。したがって、生成されたコードでは、各オーバーロードされたメソッドは別の名前を持ちます。このようにコンパイラはコンパイル時にどのメソッドを呼び出すかを知っています。

関数のオーバーライドの場合(派生クラスはその基本クラスのメソッドを再定義する)、基本クラスのメソッドが非仮想の場合、呼び出す関数はコンパイル時に決定されます。しかし、それが仮想関数であれば、コンパイラはコンパイル時にコールを解決できません。仮想テーブル参照は、オブジェクト内の仮想ポインタを介して行わなければならない。これは、実行時にのみ発生する可能性があります。実行時には、どのオブジェクトを扱っているのか知ることができるからです。

関連する問題