2011-06-09 57 views
0

在此代碼:C++ - 可以以不同的方式執行函數嗎?

void Window::oops() { printf("Window oops\n"); } 
void TextWindow::oops() { 
printf("TextWindow oops %d\n", cursorLocation); 
} 
TextWindow x; 
Window  a; 
Window  *b; 
TextWindow *c; 
a = x; a.oops(); // executes Window version 
b = &x; b->oops(); // executes TextWindow or Window version 
c = &x; c->oops(); // executes TextWindow version 

是什麼意思的是b = &x; b->oops();將執行TextWindow 窗口版本?它是如何決定的?

+0

這叫做多態性。 – twk 2011-06-09 15:27:31

回答

4

如果oops()是虛擬的,則b->oops()調用將使用TextWindow版本。如果不是,它將使用Window版本。

+0

-1代表'如果不是,它將使用Window版本',因爲它會調用'TextWindow'版本。 – Nawaz 2011-06-09 15:30:17

+1

@Nawaz:不,它不會。如果函數不是虛擬的,它將使用Window版本,因爲b的類型是Window *。 – Sven 2011-06-09 15:34:05

0
a = x; a.oops(); // executes Window version 

這一個導致對象切片。看到這個維基條目:Object slicing

b = &x; b->oops(); // executes TextWindow or Window version 

利用這一點,你多態調用虛函數。它會調用TexTWindow版本,而不是Window版本!

c = &x; c->oops(); // executes TextWindow version 

它只是調用虛擬函數,使用相同類型的指針,作爲動態的對象的類型,在這種情況下,如果TextWindow

+1

如果'oops()'是虛擬的,'b-> oops()'只會調用TextWindow的版本*,並且我們不能確定它是否來自問題中的代碼片段。 – Sven 2011-06-09 15:35:56

+0

我沒有看到'oops'聲明爲'virtual'。沒有辦法確定這些類是否來自發布的代碼段OP的「多態」。 – 2011-06-09 15:38:41

0

它的基本polymorphism

b爲一個指向窗口,它可以指向一個窗口的對象或從窗口繼承的類型的對象。然後,繼承類型可以重新實現oops()函數(如果在Window定義中oops()被指定爲虛擬的)。

爲了做到這一點,C++編譯器會添加額外的信息來在對象數據中路由函數調用,幾乎總是以v-table的形式。

這允許你操縱一組Windows,調用基本成員函數,不用擔心對象最終會做什麼。然後該對象可以以特定的子類型以特定的方式實現函數。

看到在維基百科頁面的簡單的例子:http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

1

雖然它沒有特別聲明,我假設TextWindow派生(直接或間接)從Window

在這種情況下,基本問題是oops()是否是虛擬成員函數。

如果oops()是虛擬的,則通過指針或引用的呼叫基於動態類型 - 指針/引用實際引用的對象的類型。

如果oops()不是虛擬的,然後通過一個指針或引用一個呼叫是基於靜態類型 - 指針被定義在點對象的類型,不管對象的類型的它實際上指着。

struct Window { 
    void oops() { std::cout << "Window::oops()\n"; } 
    virtual void oops2() { std::cout << "Window::oops2()\n"; } 
}; 

struct TextWindow : Window { 
    void oops() { std::cout << "TextWindow::oops()\n"; } 
    virtual void oops2() { std::cout << "TextWindow::oops2()\n"; } 
}; 

int main() { 
    Window w; 
    w.oops();  // Both of these print "Window::...". 
    w.oops2(); 

    TextWindow tw; 
    tw.oops();  // Both of these print "TextWindow::...". 
    tw.oops2(); 

    Window &w2 = tw; 
    w2.oops();  // oops() is not virtual, and we're using a reference to a Window, 
        // so this invokes Window::oops(). 

    w2.oops2(); // oops2() is virtual, so even though w2 is a reference to a 
        // Window, this invokes TextWindow::oops2(), because the reference 
        // refers to the object tw, which is a TextWindow. 

    return 0; 
} 
相關問題