詳解一道C 筆試題,考察過載 覆蓋 多型

2021-07-06 00:25:50 字數 2763 閱讀 7659

c++版看到的,說是面試寶典裡的題目,考察過載、覆蓋、多型等概念,比較有代表性。今天早上遠端輔導 yan wang 同學學習 qt 時還想到了這個題目,如果你能夠正確理解這個題目,說明對於 c++ 中的函式過載、覆蓋、虛函式、多型等有了正確的認識。然後呢,再來學習 qt 就順風順水了。

題目是醬紫的:

[cpp]view plain

copy

#include 

#include 

using

namespace

std;  

class

a    

intgetdata()  

virtual

intdogetdata()  

};  

class

b : 

public

a    

intdogetdata()  

};  

class

c : 

public

b    

};  

void

main()    

程式執行後的輸出結果是什麼?

答案是:1 1 1 1 1 0 1 1

追問一下,去掉 a 類中 dogetdata() 函式的 virtual 修飾,程式執行後的輸出結果是什麼?

答案是:0 0 0 0 1 0 1 1

說說我對這個題目的理解。

首先我們從物件的角度來看一下。

先看 main() 函式中構造 c 物件的語句:

[cpp]view plain

copy

c c(10);  

這句產生下面的效果:

為什麼呢?

c c(10); 這行**,定義了 c 物件,但實際上記憶體中有三個物件:

class c 的例項物件,即 c

由於 c 是 b 的派生類,會產生乙個 class b 例項物件,即 (b)c

由於 b 是 a 的派生類,會產生乙個 a 例項物件,即 (a)c

每個物件都有 m_data 成員變數, 根據繼承關係,子類覆蓋父類的同名成員(變數、函式), c 物件中實際上有三個同名的 m_data 變數,你通過不同的身份去看,會看到不同的 m_data 。

c 物件生成時,呼叫 b 、a 類的建構函式,對 b 、 a 初始化,結果就是:

這就是我們一開始給出的效果。

明白了物件的關係和 m_data 成員的值。咱們再來看 getdata() 函式。

getdata() 函式是 class a 的乙個普通方法,根據繼承關係, b 、 c 類都可以訪問 getdata() 方法,因為 b 、 c 沒有重寫 getdata() ,所以通過 b 、 c 的物件訪問 getdata() ,訪問的都是 a 的 getdata() 方法。

在 getdata() 中,呼叫了 dogetdata() ,注意了,這是個虛函式!如果 a 的後裔重寫了 dogetdata() 函式,那麼這裡實際上會呼叫到繼承關係上處於最底層的那個類的 dogetdata() 函式,這就是虛函式和多型的概念。如你所見, b 重寫了 dogetdata() 函式,所以當你呼叫 c.getdata() , b 的 dogetdata() 會被呼叫, ((b)c).m_data 被返回。其實在 qt 中,這種用法比比皆是。

好啦,下面分析 main() 函式的輸出結果。

dogetdata() 帶 virtual 關鍵字

c.a::getdata() / c.getdata() / c.b::getdata() / c.c::getdata()

這些語句,都是呼叫 a::getdata() ,最終都呼叫 ((b)c).dogetdata(), 就是b::dogetdata() ,訪問的是 b 的物件,它的 m_data = 1 ,所以 dogetdata() 返回 1 ,最終 getdata() 返回 1 。

c 類沒有定義 dogetdata() 函式,c.dogetdata() 等同於 ((b)c).dogetdata() , 訪問的是 b 的物件,它的 m_data = 1 ,所以 c.dogetdata() 結果是 1 。

c.a::dogetdata() ,類域作用符限定了呼叫 a::dogetdata(),訪問 a 的物件,返回 ((a)c).m_data = 0 。

c.b::dogetdata() / c.c::dogetdata() 最終都是訪問 b 物件的 dogetdata() 方法, 返回都是 1 。

所以 dogetdata() 帶 virtual 關鍵字,程式輸出 1 1 1 1 1 0 1 1 。

去掉 dogetdata() 的 virtual 關鍵字

因為 getdata() 是 a 類的方法,而 dogetdata() 不是虛函式, a 類的 getdata() 內呼叫的 dogetdata() 方法只可能是 a 的物件的方法,((a)c).m_data = 0 ,所以前四個cout結果都是 0 。

c.dogetdata() ,c 的物件內沒有實現這個函式,呼叫父類的,即 b 的物件的 dogetdata() 方法,訪問的 m_data 是 ((b)c) 物件的,是 1 。

c.a::dogetdata() ,呼叫 a 的方法,訪問 a 的物件 ((a)c).m_data ,結果是 0 。

c.b::dogetdata() / c.c::dogetdata() ,呼叫 b 的方法,訪問 b 的物件 ((b)c).m_data ,結果為 1 。

所以,最終結果是:0 0 0 0 1 0 1 1

詳解一道C 筆試題,考察過載 覆蓋 多型

題目是醬紫的 cpp view plain copy include include using namespace std class a intgetdata virtual intdogetdata class b public a intdogetdata class c public b ...

詳解一道C 筆試題,考察過載 覆蓋 多型

c 版看到的,說是面試寶典裡的題目,考察過載 覆蓋 多型等概念,比較有代表性。今天早上遠端輔導 yan wang 同學學習 qt 時還想到了這個題目,如果你能夠正確理解這個題目,說明對於 c 中的函式過載 覆蓋 虛函式 多型等有了正確的認識。然後呢,再來學習 qt 就順風順水了。題目是醬紫的 inc...

一道verilog筆試題考察的generate特性

可以動態的生成verilog 當對向量中的多個位進行重複操作時,或者當進行多個模組的例項引用的重複操作時,或者根據引數的定義來確定程式中是否應該包含某段verilog 的時候,使用生成語句能大大簡化程式的編寫過程。生成語句生成的例項範圍,關鍵字generate endgenerate用來指定該範圍。...