2012-03-29 43 views
2

爲什麼重寫在運行時解決,而重載在編譯時解決?
是否有任何理由,重寫不能在編譯時解決。C++重載和重寫解析時間

+0

你告訴我們 - 在編譯時如何解決_could_ overriding問題? – ildjarn 2012-03-29 03:30:30

+0

@ildjarn:你可能想檢查我的答案下的評論鏈接。 – 2012-03-29 03:56:05

+0

@Als:動態多態性完全是_disabled_(因此與問題/對話無關)的上下文不是我所問的。顯然,爲了使用多態性,必須處於多態環境中。 – ildjarn 2012-03-29 04:40:44

回答

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()什麼都不知道是很重要的關於b究竟是什麼(它可能指的是Base實例或Derived實例)。所有CallFoo() gets都是對Base的引用,它沒有提及它實際引用的內容,所以編譯器無法知道它在編譯CallFoo()時是什麼。因此,確定是應該調用Base::Foo()還是Derived::Foo()必然是運行時決策。

卸下virtual關鍵字(禁用壓倒一切的)將導致上述代碼以打印出Base::Foo()兩次,不Base::Foo()然後Derived::Foo()。這是因爲如果沒有關鍵字virtual,編譯器會在編譯時簡單地將調用解析爲Base::Foo()。這就是說,由於虛函數會產生一些開銷(畢竟,需要調用的正確函數是運行時決策),編譯器會盡力找出b的實際類型CallFoo(),如果可以的話。在這種情況下,它將成爲編譯時決定。但是,它是一個實現細節。

2

覆蓋僅在虛擬功能的運行時被解決,因爲這就是dynamic binding的實現方式。非虛函數調用在編譯時解析。

2

爲什麼重寫是在運行時解決的,而重載是在編譯時解決的?

它實際上取決於。
通常,編譯器無法確定在overidding情況下直接調用的實際函數。這是因爲基類指針可能不知道的實際對象直到運行時。在這種情況下,編譯器無法在運行時解析實際的函數調用。
但是,有時候編譯器可以巧妙地檢測到即使在overidding的情況下也需要調用的函數,並且在這種情況下它們可以解析在編譯時調用的函數。

在重載的情況下,被調用的實際函數可以由編譯器根據傳遞給函數的參數來確定,所以編譯器不需要等到運行時解析這樣的調用,因爲所有的參數類型都是在編譯時已知,因爲C++是一種靜態類型語言,編譯時必須知道所有類型。

+0

'有時編譯器可以巧妙地和確定地檢測到即使在overidding的情況下也需要調用的函數。您是否有這樣的例子? – 2012-03-29 03:19:35

+0

@Jesse:Check out:[什麼時候編譯器靜態地綁定一個虛擬函數調用?](http://stackoverflow.com/questions/7291596/when-can-the-compiler-statically-bind-a-call對一個虛函數),是的我所引用的是一個非常成熟的事實。這裏沒有任何猜測。 – 2012-03-29 03:30:35

+1

感謝您的鏈接! – 2012-03-29 03:46:20

0

C++中的函數重載可以由編譯器自己處理。在函數重載期間,編譯器「裝飾」函數名稱,技術上稱爲name mangling。所以在生成的代碼中,每個重載的方法都會有一個單獨的名稱。這樣編譯器知道在編譯時本身調用哪個方法。

在函數重寫(派生類重新定義其基類中的方法)的情況下,如果基類方法是非虛擬的,則在編譯時本身確定要調用的函數。但是如果它是一個虛函數,那麼編譯器無法在編譯時解析調用。虛擬表查找必須通過對象中的虛擬指針發生。這隻會在運行時發生,因爲只有在運行時你纔會知道你正在處理哪個對象。