日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)

發布時間:2024/4/17 c/c++ 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. sizeof計算結構體

  注:本機機器字長為64位

1.最普通的類和普通的繼承


#include<iostream> using namespace std;class Parent{ public:void fun(){cout<<"Parent fun"<<endl;} }; class Child : public Parent{ public:void fun(){cout<<"Child fun"<<endl;}char ch[5]; };int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; }/*運行結果:Parent size : 1, Child size : 5 */

分析:那么為什么類(對象)的大小為什么會是1個字節呢?那是被編譯器插進去的一個char ,使得這個class的不同實體(object)在內存中配置獨一無二的地址。也就是說這個char是用來標識類的不同對象的。因為如果不是1,當定義這個類的對象數組時候A objects[5]; objects[0]和objects[1]就在同一個地址處,就無法區分。

2.基類中含有私有成員


#include<iostream> using namespace std;class Parent{ public:void fun(){cout<<"Parent fun"<<endl;} private:int x; }; class Child : public Parent{ public:void fun(){cout<<"Child fun"<<endl;}char ch[5]; };int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; } /*執行結果:Parent size : 4, Child size : 12 */

分析:基類里的私有成員在派生類里仍占有內存。在派生類里,基類的int占4個字節,char ch[5]占用5個字節,考慮內存的對齊,變成4+(5+3)=12個字節。

?

3.類中含有虛函數


#include<iostream> using namespace std;class Parent{ public:virtual void fun(){cout<<"Parent fun"<<endl;} }; class Child : public Parent{ public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5]; };int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; } /*執行結果:Parent size : 8, Child size : 16 */

分析:有虛函數的類有個virtual table(虛函數表),里面包含了類的所有虛函數,類中有個virtual table pointers,通常成為vptr指向這個virtual table,占用8個字節的大小。成員類Child public繼承于Parent,類Child的虛函數表里實際上有兩個虛函數Parent::fun()和Child::hjzgg(),類B的大小等于char ch[5]的大小加上一個指向虛函數表指針vptr的大小,考慮內存對齊為16。一個類里若有虛函數,無論有多少個虛函數都只有一個指向虛表的指針,虛表中的每一個表項保存著一個虛函數的入口地址。當調用虛函數時,先找到虛表中它對應的表項,找到入口地址再執行

4.多重繼承


#include<iostream> using namespace std;class Parent{ public:virtual void fun(){cout<<"Parent fun"<<endl;} }; class Father{ public:virtual void fun(){cout<<"Father fun"<<endl;} };class Child : public Parent, public Father{ public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5]; };int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; } /*執行結果:Parent size : 8, Child size : 24 */

分析:Child中除了char ch[5]這5個字節,Child現有一個虛函數表,里邊有Child自身定義的虛函數以及從Parent中繼承過來的虛函數,然后又另一張虛函數表來存放Father中過來的虛函數,也就是Child對應兩個虛函數表的指針。總共內存空間5+8+8=21,考慮內存的對齊,為24字節。

?5.虛繼承

  C++虛擬繼承

  ◇概念:

   ? C++使用虛擬繼承(Virtual Inheritance),解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致問題,將共同基類設置為虛基類。 ? ? ? ? ?這時從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝,同一個函數名也只有一個映射。

  ◇解決問題:

  解決了二義性問題,也節省了內存,避免了數據不一致的問題。?  同義詞:   虛基類(把一個動詞當成一個名詞而已)   當在多條繼承路徑上有一個公共的基類,在這些路徑中的某幾條匯合處,這個公共的基類就會產生多個實例(或多個副本),若只想保存這個基類的一個實例,可以將這個 公共基類說明為虛基類。

  ◇執行順序

   ??首先執行虛基類的構造函數,多個虛基類的構造函數按照被繼承的順序構造;

   執行基類的構造函數,多個基類的構造函數按照被繼承的順序構造;

   執行成員對象的構造函數,多個成員對象的構造函數按照申明的順序構造;

   執行派生類自己的構造函數;

   ??析構以與構造相反的順序執行;

  注:

   ?從虛基類直接或間接派生的派生類中的構造函數的成員初始化列表中都要列出對虛基類構造函數的調用。但只有用于建立對象的最派生類的構造函數調用虛基類 ? ? ? ? ? 的構造函數而該派生類的所有基類中列出的對虛基類的構造函數的調用在執行中被忽略,從而保證對虛基類子對象只初始化一次。

   ?在一個成員初始化列表中同時出現對虛基類和非虛基類構造函數的調用時,虛基類的構造函數先于非虛基類的構造函數執行。

?5.1?沒有用虛擬繼承


#include<iostream> using namespace std;class Parent{ public:virtual void fun(){cout<<"Parent fun"<<endl;} }; class Father{ public:virtual void fun(){cout<<"Father fun"<<endl;} };class Child : public Parent, public Father{ public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5]; };int main(){Parent p;Child ch;ch.fun();ch.Parent::fun();//這樣調用是對的ch.Father::fun();cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; } /*執行結果:[Error] request for member 'fun' is ambiguous */

分析:因為派生類中的虛函數表會繼承來自各個基類的虛函數。所以Child對應的虛函數表中會有Parent 和 Father各自的fun()函數,所以在調用的時候就會出現歧義,不知道應該調用哪個!

  同樣,和下面一樣的寫法也是錯誤的,增加一個Super類。


#include<iostream> using namespace std;class Super{ public:virtual void fun(){cout<<"Super fun"<<endl;} };class Parent : public Super{ public:}; class Father : public Super{ public:};class Child : public Parent, public Father{ public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5]; };int main(){Parent p;Child ch;ch.fun();cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0; }/*執行結果:[Error] request for member 'fun' is ambiguous */
5.2 使用虛擬繼承#include<iostream>?


using namespace std;class Super{ public:Super(){cout<<"Super construction"<<endl;}virtual void fun(){cout<<"Super fun"<<endl;} };class Parent : virtual public Super{ public:Parent(){cout<<"Parent construction"<<endl;} }; class Father : virtual public Super{ public:Father(){cout<<"Father construction"<<endl;} };class Child : public Parent, public Father{ public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5]; };int main(){Child ch;ch.fun();cout<<"Parent size : "<<sizeof(Parent)<<", Child size : "<<sizeof(Child) <<endl;return 0; } /*執行結果:Super constructionParent constructionFather constructionSuper funParent size : 8, Child size : 24*/

分析:

  1.在多繼承情況下,虛基類關鍵字的作用范圍和繼承方式關鍵字相同,只對緊跟其后的基類起作用。   2.聲明了虛基類之后,虛基類在進一步派生過程中始終和派生類一起,維護同一個基類子對象的拷貝。(Super的構造函數只執行了一次,如果不是有虛基類,那么Super的構造函數 將會執行兩次。)   3.觀察類構造函數的構造順序,拷貝也只有一份。

二. c++重載、覆蓋、隱藏的區別和執行方式

  1.成員函數被重載的特征
(1)相同的范圍(在同一個類中);?
(2)函數名字相同;?
(3)參數不同;?
(4)virtual 關鍵字可有可無。?
  2.“覆蓋”是指派生類函數覆蓋基類函數,特征是:
(1)不同的范圍(分別位于派生類與基類);?
(2)函數名字相同;?
(3)參數相同;?
(4)基類函數必須有virtual 關鍵字。?
  3.“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,特征是:

  (1)不同的范圍(分別位于派生類與基類);

  (2)如果派生類的函數與基類的函數同名,但是參數不同,此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。?
(3)如果派生類的函數與基類的函數同名,且參數相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。

  小結:說白了就是如果派生類和基類的函數名和參數都相同,屬于覆蓋,這是可以理解的吧,完全一樣當然要覆蓋了;如果只是函數名相同,參數并不相同,則屬 于隱藏。

總結

以上是生活随笔為你收集整理的c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。