[C++面試題]之繼承與介面

來源:互聯網
上載者:User
文章目錄
  • 1、以下代碼的輸出結果是什嗎?
  • 2、以下代碼輸出結果是什嗎?
  • 3、衍生類別的3種繼承方式?
  • 4、下面程式運行結果是什嗎?
  • 5、什麼是虛繼承?它與一般的繼承有什麼不同?它有什麼用?寫出一段虛繼承的C++代碼。

     整個C++程式設計全面圍繞物件導向的方式進行。類的繼承特性是C++的一個非常重要的機制。繼承特性可以使一個新類獲得其父類的操作和資料結構,程式員只需在新類中增加原有類沒有的成分。

     在面試過程中,各大企業會考量你對虛函數、純虛函數、私人繼承、多重繼承等知識點的掌握程度,因此就有了我們這一節的內容,開始吧。

1、以下代碼的輸出結果是什嗎?
#include<iostream>using namespace std;class A{protected:int m_data;public:A(int data = 0){m_data = data;}int GetData(){return doGetData();}virtual int doGetData(){return m_data;}};class B : public A{protected:int m_data;public:B(int data = 1){m_data = data;}int doGetData(){return m_data;}};class C : public B{protected:int m_data;public:C(int data = 2){m_data = data;}};int main (){C c(10);cout << c.GetData() <<endl;cout << c.A::GetData() <<endl;cout << c.B::GetData() <<endl;cout << c.C::GetData() <<endl;cout << c.doGetData() <<endl;cout << c.A::doGetData() <<endl;cout << c.B::doGetData() <<endl;cout << c.C::doGetData() <<endl;return 0;}

     解析:建構函式從最初始的基類開始構造的,各個類的同名變數沒有形成覆蓋,都是單獨的變數.理解這兩個重要的C++特性後解決這個問題就比較輕鬆了,下面我們看看:

     cout << c.GetData() <<endl;

     本來是要調用C類的GetData(),C中未定義,故調用B中的,但是B中也未定義,故調用A中的GetData(),因為A中的doGetData()是虛函數,所以調用B類中的doGetData(),而B類的doGetData()返回B::m_data,故輸出 1。

     cout << c.A::GetData() <<endl;

     因為A中的doGetData()是虛函數,所以調用B類中的doGetData(),而B類的doGetData()返回B::m_data,故輸出 1。

     cout << c.B::GetData() <<endl;

     肯定是B類的傳回值 1 了。

     cout << c.C::GetData() <<endl;

     跟cout << c.GetData() <<endl;語句是一樣的。

 

     cout << c.doGetData() <<endl;

     B類的傳回值 1 了。

     cout << c.A::doGetData() <<endl;

     因為直接調用了A的doGetData() ,所以輸出0。

     cout << c.B::doGetData() <<endl;

     cout << c.C::doGetData() <<endl;

     這兩個都是調用了B的doGetData(),所以輸出 1。

     這裡要注意存在一個就近調用,如果父類存在相關介面則優先調用父類介面,如果父類也不存在相關介面則調用祖父輩介面。

答案:

1 1 1 1 1 0 1 1

 

2、以下代碼輸出結果是什嗎?
#include<iostream>using namespace std;class A{public:void virtual f(){cout<<"A"<<endl;}};class B : public A{public:void virtual f(){cout<<"B"<<endl;}};int main (){A* pa=new A();pa->f();B* pb=(B*)pa;pb->f();delete pa,pb;pa=new B();pa->f();pb=(B*)pa;pb->f();return 0;}

        解析:這是一個虛函數覆蓋虛函數的問題。A類裡的f()函數是一個虛函數,虛函數是被子類同名函數所覆蓋的。而B類裡的f()函數也是一個虛函數,它覆蓋A類f()函數的同時,也會被它的子類覆蓋。但是在 B* pb=(B*)pa;裡面,該語句的意思是轉化pa為B類型並建立一個指標pb,將pa複製到pb。但是這裡有一點請注意,就是pa的指標始終沒有發生變化,所以pb也指向pa的f()函數。這裡並不存在覆蓋的問題。

      delete pa,pb;刪除了pa和pb所指向的地址,但是pa、pb指標並沒有刪除,也就是我們通常說的懸浮指標,現在重新給pa指向新地址,所指向的位置是B類的,而之前pa指標類型是A類的,所以就產生了一個覆蓋。pa->f();的值是B。

      pb=(B*)pa;轉化pa為B類指標給pb賦值,但pa所指向的f()函數是B類的f() 函數,所以pb所指向的f()函數是B類的f()函數。pb->f();的值是B。

       答案:

A A B B

 

3、衍生類別的3種繼承方式?

       答案:

    (1)公有繼承方式:

     基類成員對其對象的可見度與一般類及其對象的可見度相同,公有成員可見,其他成員不可見。這裡保護成員與私人成員相同。

     基類成員對衍生類別的可見度對衍生類別來說,基類的公有成員和保護成員可見,基類的公有成員和保護成員作為衍生類別的成員時,它們都保持原有的狀態;基類的私人成員不可見,基類的私人成員仍然是私人的,衍生類別不可訪問基類中的私人成員。

     基類成員對衍生類別對象的可見度對衍生類別對象來說,基類的公有成員是可見的,其他成員是不可見的。

    (2)私人繼承方式:

     基類成員對其對象的可見度與一般類及其對象的可見度相同,公有成員可見,其他成員不可見。

     基類成員對衍生類別的可見度對衍生類別來說,基類的公有成員和保護成員可見,基類的公有成員和保護成員都作為衍生類別的私人成員,並且不能被這個衍生類別的子類所訪問;基類的私人成員不可見,衍生類別不可訪問基類中的私人成員。

     基類成員對衍生類別對象的可見度對衍生類別對象來說,基類的所以成員都是不可見的。

     所以說,在私人繼承時,基類的成員只能由直接衍生類別訪問,而無法再往下繼承。

    (3)保護繼承方式:

     這種繼承方式與私人繼承方式的情況相同,兩者的區別僅在於對衍生類別的成員而言,基類成員對其對象的可見度與一般類及其對象的可見度相同,公有成員可見,其他成員不可見。

     基類成員對衍生類別的可見度對衍生類別來說,基類的公有成員和保護成員可見,基類的公有成員和保護成員都作為衍生類別的保護成員,並且不能被這個衍生類別的子類所訪問;基類的私人成員不可見,衍生類別不可訪問基類中的私人成員。

     基類成員對衍生類別對象的可見度對衍生類別對象來說,基類的所以成員都是不可見的。

     所以說,在私人繼承時,基類的成員只能由直接衍生類別訪問,而無法再往下繼承。

 

4、下面程式運行結果是什嗎?
#include<iostream>using namespace std;class A{char k[3];public:virtual void aa(){};};class B : public virtual A{char j[3];public:virtual void bb(){};};class C : public virtual B{char i[3];public:virtual void cc(){};};int main (){cout << "sizeof(A):" << sizeof(A) << endl;cout << "sizeof(B):" << sizeof(B) << endl;cout << "sizeof(C):" << sizeof(C) << endl;return 0;}

      解析:(1)對於A類,由於有一個虛函數,那麼必須有一個對應的虛函數表來記錄對應的函數入口地址。每個地址需標有一個虛指標,指標的大小為4。類中還有一個char k[3],每一個char值所佔空間是1,所以char k[3]所佔大小是3。做一個資料對齊後變為4。所以,sizeof(A)的結果就是char k[3]所佔大小4和虛指標所佔大小4之和等於8。

    (2)對於B類,由於B繼承了A,同時還擁有自己的虛函數,那麼B中首先擁有一個vfptr_B,指向自己的虛函數表。還有char j[3],大小為4,可虛繼承該如何?呢?首先要通過加入一個虛類指標(記vbptr_B_A)來指向其父類,然後還要包含父類的所有內容,所以sizeof(B)的大小是:A類所佔大小8,char j[3]所佔大小4,vfptr_B所佔大小4,vbptr_B_A所佔大小4,它們之和等於20。

    (3)對於C類和B類差不多,結果是32。

     答案:

sizeof(A):8

sizeof(B):20

sizeof(C):32

 

5、什麼是虛繼承?它與一般的繼承有什麼不同?它有什麼用?寫出一段虛繼承的C++代碼。

    答案:

虛擬繼承是多重繼承中特有的概念。虛擬基類是為瞭解決多重繼承而出現的,請看:

 

在圖 1中,類D接觸自類B和類C,而類B和類C都繼承自類A,因此出現了圖 2所示的情況。

在圖 2中,類D中會出現兩次A。為了節省記憶體空間,可以將B、C對A的繼承定義為虛擬繼承,而A成了虛擬基類。最後形成了圖 3。

代碼如下:

class A;class B : public virtual A;class C : public virtual A;class D : public B,public C;

 

     繼承與介面這一節寫完了,感覺收穫很多啊,希望你們也和我一樣。因為本人算是初學者,所以很多知識點說得不夠簡練,甚至不正確的,請多多包涵和指正。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.