2015-04-18 83 views
2

假設我有以下類:重寫重載方法隱藏了一些重載的

class Base 
{ 
public: 
    virtual void myMethod() 
    { 

    } 

    virtual void myMethod(int x) 
    { 

    } 
}; 

class Derived : public Base 
{ 
}; 

在這種情況下,下面的代碼編譯就好了。

int main(void) 
{ 
    Derived obj; 
    obj.myMethod(); 

    return (0); 
} 

當我嘗試覆蓋下面的其中一個myMethod s時出現問題。

class Derived : public Base 
{ 
public: 
    virtual void myMethod(int x) 
    { 

    } 
}; 

現在的代碼將無法編譯,並給出錯誤:

error C2660: 'Derived::myMethod' : function does not take 0 arguments

我已經覆蓋的重載函數之一,顯然這已經藏了Derived類另一個。爲了擺脫這個錯誤,我必須覆蓋所有的重載。這違背了我的期望,對我來說似乎不合理。爲什麼此代碼的行爲如此?

該問題可以複製here

+0

它隱藏*所有*繼承的重載。 – EJP

回答

1

你的編譯器是100%正確的。
你重載了你的函數來取一個整數作爲參數,那麼這個函數隱藏了所有的基類函數 - 所以obj調用myMethod(int)是默認的,但是你不提供你的函數一個整數。 如果您修復您的代碼爲 obj.myMethod(4);

問題已解決。

當重寫派生類中的函數時 - 它隱藏了所有其他基類重載。仍然可以用以下語法調用基類: obj.Base::myMethod();

在更深入的答案中,這是爲什麼會發生這種情況。首先,我們需要了解編譯器如何編譯面向對象的代碼。記住 - 函數編譯成彙編命令,它們位於code segment。變量會編譯成在堆棧,堆或數據段中枯萎的內存行。函數位於應用程序的一部分中,變量處於完全不同的區域。編譯器如何編譯帶有變量和函數的類?好吧,它不。這個想法是這樣的:

比方說,一個有一些變量和一些功能名爲X類
1)把所有的成員函數,並把他們趕出類
2)中添加其他參數給每個-現在 - 全球宣佈的功能 - const X* this
3)每次看到語法x.someFunc(args..)改變它是someFunc(args..,&x)
4)功能時 - 如果你不認識的符號 - 嘗試將其附着一個this->,看你是否能編譯這個
5)將X編譯爲C結構,將另一個編譯爲C函數
6)對派生的c lasses (當然,有虛表的問題,但讓我們停在這裏)

在你的榜樣:
可能代表編譯器分析代碼的僞代碼

struct Base{} 
struct Derived{} 

void myMethod(const Base* this); 
void myMethod(int x,const Base* this); 
void myMethod(int x, const Derived* this); 

//what you tried to do is : 
myMethod (&obj); 

但編譯器找不到與這些參數匹配的任何函數!對於一開始並不知道面向對象編譯的人來說,這並不是非常直觀,但是在理解了這個編譯過程之後,它會變得更有意義。

+0

那麼問題是爲什麼編譯器會隱藏其他重載?我沒有要求那個!我只是重寫其中一個重載。 – atoMerz

+0

,因爲這是一個C++規則。當你重寫一個函數時,它會隱藏所有其他具有相同名字的基類函數。你仍然可以使用obj.Base :: myMethod()來調用基類。 –

+0

任何引用回來了嗎? – atoMerz

0

事實上,在一個作用域中聲明一個函數會隱藏更廣泛範圍內的相同名稱的任何東西,因此您在派生類中的重寫將隱藏基類中的重載。

這通常不是問題,因爲您通常會通過基類與多態類進行交互;並且通常是你想要的,因爲它可以防止基類的更改意外地改變與派生類進行交互的代碼的行爲。

但是你可以很容易地把它放回派生類的範圍,如果你想:

using Base::myMethod; 

或由有資質的名字來描述功能:

obj.Base::myMethod(); 
0

通過在派生類中重寫功能您可以隱藏基類中存在的該函數名稱的所有重載實現。

因此,重寫void Base::myMethod(int)void Derived::myMethod(int)只生成代碼void Derived::myMethod(int)而不是void Derived::myMethod()

如前所述,您可以明確調用Base的函數: obj.Base::myMethod()