C 的秘密之過載,覆蓋,和隱藏

2021-06-09 04:57:38 字數 2478 閱讀 4166

過載(overload):

必須在乙個域中,函式名稱相同但是函式引數不同,過載的作用就是同乙個函式有不同的行為,因此不是在乙個域中的函式是無法構成過載的,這個是過載的重要特徵

覆蓋(override):

覆蓋指的是派生類的虛函式覆蓋了基類的同名且引數相同的函式,既然是和虛函式掛鉤,說明了這個是乙個多型支援的特性,所謂的覆蓋指的是用基類物件的指標或者引用時訪問虛函式的時候會根據實際的型別決定所呼叫的函式,因此此時派生類的成員函式可以"覆蓋"掉基類的成員函式。

注意唯有同名且引數相同還有帶有virtual關鍵字並且分別在派生類和基類的函式才能構成虛函式,這個也是派生類的重要特徵。

而且,由於是和多型掛鉤的,所以只有在使用類物件指標或者引用的時候才能使用上。

總之一句話:覆蓋函式都是虛函式,反之不然~~

隱藏(hide):

指的是派生類的成員函式隱藏了基類函式的成員函式。隱藏一詞可以這麼理解:在呼叫乙個類的成員函式的時候,編譯器會沿著類的繼承鏈逐級的向上查詢函式的定義,如果找到了那麼就停止查詢了,所以如果乙個派生類和乙個基類都有同乙個同名(暫且不論引數是否相同)的函式,而編譯器最終選擇了在派生類中的函式,那麼我們就說這個派生類的成員函式"隱藏"了基類的成員函式,也就是說它阻止了編譯器繼續向上查詢函式的定義…

回到隱藏的定義中,前面已經說了有virtual關鍵字並且分別位於派生類和基類的同名,同引數函式構成覆蓋的關係,因此隱藏的關係只有如下的可能:

1)必須分別位於派生類和基類中

2)必須同名

3)引數不同的時候本身已經不構成覆蓋關係了,所以此時是否是virtual函式已經不重要了

當引數相同的時候就要看時候有virtual關鍵字了,有的話就是覆蓋關係,沒有的時候就是隱藏關係了

上面的解說大體把三者的區別給說清楚了,但是還有一些疑惑的地方,以下以**例子說明。

很多人分辨不清隱藏和覆蓋的區別,因為他們都是發生在基類和派生類之中的。但是它們之間最為重要的區別就是:

覆蓋的函式是多型的,是存在於vtbl之中的函式才能構成"覆蓋"的關係,而隱藏的函式都是一般的函式,不支援多型,在編譯階段就已經確定下來了。

class base

void g( float x)

} ;class derived: public base

void g( int x)

} ;int main()

[nextpage]

在呼叫f函式的時候,派生類derived的f函式覆蓋了基類base的f函式,而派生類derived的g函式隱藏了基類base的g函式。

為什麼?理由很簡單,f函式是virtual函式,但是g函式不是。我們可以把base類和derived類看成這樣的乙個struct:

struct base

;void __baseg(float)

struct derived

;void __derivedg(float)

struct vtable

;void __basef(float)

void __derivedf(float)

在程式編譯的時候,函式指標f就已經是確定的了,但是__vptr根據不同的而有分別,而這個變化是執行期動態決定的。

回到上面的例子中,base *pb=&d;的時候只是用derived類物件d的__vptr修改了base類pb的__vptr指標,但是當base類成員建立的

時候f函式指標就是不能改變的。

當函式被宣告為virtual的時候,就啟用了多型機制,程式在執行的時候會根據型別的實際型別到vtable中查詢函式指標,因此對函式g的呼叫就是這樣子的:

pb->__vptr->g();

而對f的呼叫就是一般的類成員函式指標的呼叫了:pb->f(),因為這個型別在程式編譯的時候已經確認了,所以在程式執行的時候是不能發生改變的。

綜上,可以把

derived d;

base *pb=&d;

的過程分解為:

d.g = __derivedg;

d.__vptr->f = __derivedf;

pb->g = __baseg; // 這裡根據指標的真正型別確定函式指標

pb->__vptr = d.__vptr; // 這裡只是簡單的指標賦值,因此訪問到的就是derived的函式了

最後在呼叫:

pb->f(3.14f);

pb->g(3.14f);

實際上是:

pb->__vptr->__derivedf(3.14f);

__baseg(3.14f);

這麼寫就明白最後在呼叫的時候為什麼會用那樣的結果了,可以看出多了乙個__vptr這個間接層實現了所謂的"動態繫結".

最後,需要說明的一點是:實際上在c++中,非static和非virtual的函式指標並不會在乙個class中儲存它的函式指標,上面把函式g的指標寫在struct裡面只是為了方便說明這樣的問題:在編譯階段這個函式就已經是確定的不可改變的了。特此說明一下。

C 之過載覆蓋和隱藏

繼承體系下同名成員函式的三種關係 在同一作用域內 函式名相同,引數列表不同 分三種情況 引數個數不同,引數型別不同,引數個數和型別都不同 返回值型別可以相同也可以不同 在不同作用域內,分別在父類和子類 函式名相同,引數列表相同,返回值型別相同,協變除外 下面會介紹什麼是協變 基類函式必須有virtu...

C 過載 覆蓋 和隱藏

這幾個概念都有乙個共同點 函式名稱相同,所以不免讓人混淆,大致的區別如下 過載 overload 必須在乙個域中,函式名稱相同但是函式引數不同,過載的作用就是同乙個函式有不同的行為,因此不是在乙個域中的函式是無法構成過載的,這個是過載的重要特徵 覆蓋 override 覆蓋指的是派生類的虛函式覆蓋了...

C 過載 覆蓋和隱藏

過載 覆蓋和隱藏 共同點 函式名稱相同。1 過載 必須在乙個域內,函式名稱相同但是函式引數不同。過載的作用就是同乙個函式有不同的行為。過載完全是乙個編譯時 或靜態 的概念。如果宣告了同名函式,編譯器會在編譯時處理這些同名函式的呼叫問題,確定呼叫哪乙個函式,執行時不 涉及呼叫過載函式的額外開銷或決定。...