国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

常見C++面試題及基本知識(shí)點(diǎn)總結(jié)(一)

2019-11-10 20:52:47
字體:
供稿:網(wǎng)友

1. 結(jié)構(gòu)體和共同體的區(qū)別。

定義:

結(jié)構(gòu)體struct:把不同類型的數(shù)據(jù)組合成一個(gè)整體,自定義類型。

共同體union:使幾個(gè)不同類型的變量共同占用一段內(nèi)存。

地址:

struct和union都有內(nèi)存對(duì)齊,結(jié)構(gòu)體的內(nèi)存布局依賴于CPU、操作系統(tǒng)、編譯器及編譯時(shí)的對(duì)齊選項(xiàng)。

復(fù)制代碼
關(guān)于內(nèi)存對(duì)齊,先讓我們看四個(gè)重要的基本概念:1.數(shù)據(jù)類型自身的對(duì)齊值:對(duì)于char型數(shù)據(jù),其自身對(duì)齊值為1,對(duì)于short型為2,對(duì)于int,float,double類型,其自身對(duì)齊值為4,單位字節(jié)。2.結(jié)構(gòu)體或者類的自身對(duì)齊值:其成員中自身對(duì)齊值最大的那個(gè)值。3.指定對(duì)齊值:#PRagma pack(n),n=1,2,4,8,16改變系統(tǒng)的對(duì)齊系數(shù)4.數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對(duì)齊值:自身對(duì)齊值和指定對(duì)齊值中小的那個(gè)值。復(fù)制代碼

 常見數(shù)據(jù)類型及其長(zhǎng)度:

注意long int和int一樣是4byte,long double和double一樣是8byte。

在標(biāo)準(zhǔn)c++中,int的定義長(zhǎng)度要依靠你的機(jī)器的字長(zhǎng),也就是說,如果你的機(jī)器是32位的,int的長(zhǎng)度為32位,如果你的機(jī)器是64位的,那么int的標(biāo)準(zhǔn)長(zhǎng)度就是64位。

從上面的一段文字中,我們可以看出,首先根據(jù)結(jié)構(gòu)體內(nèi)部成員的自身對(duì)齊值得到結(jié)構(gòu)體的自身對(duì)齊值(內(nèi)部成員最大的長(zhǎng)度),如果沒有修改系統(tǒng)設(shè)定的默認(rèn)補(bǔ)齊長(zhǎng)度4的話,取較小的進(jìn)行內(nèi)存補(bǔ)齊。

結(jié)構(gòu)體struct:不同之處,stuct里每個(gè)成員都有自己獨(dú)立的地址。sizeof(struct)是內(nèi)存對(duì)齊后所有成員長(zhǎng)度的加和。

共同體union:當(dāng)共同體中存入新的數(shù)據(jù)后,原有的成員就失去了作用,新的數(shù)據(jù)被寫到union的地址中。sizeof(union)是最長(zhǎng)的數(shù)據(jù)成員的長(zhǎng)度。

總結(jié): struct和union都是由多個(gè)不同的數(shù)據(jù)類型成員組成, 但在任何同一時(shí)刻, union中只存放了一個(gè)被選中的成員, 而struct的所有成員都存在。在struct中,各成員都占有自己的內(nèi)存空間,它們是同時(shí)存在的。一個(gè)struct變量的總長(zhǎng)度等于所有成員長(zhǎng)度之和。在Union中,所有成員不能同時(shí)占用它的內(nèi)存空間,它們不能同時(shí)存在。Union變量的長(zhǎng)度等于最長(zhǎng)的成員的長(zhǎng)度。對(duì)于union的不同成員賦值, 將會(huì)對(duì)其它成員重寫, 原來成員的值就不存在了, 而對(duì)于struct的不同成員賦值是互不影響的。

 


 

 2.static 和const分別怎么用,類里面static和const可以同時(shí)修飾成員函數(shù)嗎。

 static的作用:

對(duì)變量:

1.局部變量:

在局部變量之前加上關(guān)鍵字static,局部變量就被定義成為一個(gè)局部靜態(tài)變量。

  1)內(nèi)存中的位置:靜態(tài)存儲(chǔ)區(qū)

  2)初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被程序自動(dòng)初始化為0(自動(dòng)對(duì)象的值是任意的,除非他被顯示初始化)

  3)作用域:作用域仍為局部作用域,當(dāng)定義它的函數(shù)或者語句塊結(jié)束的時(shí)候,作用域隨之結(jié)束。

 注:當(dāng)static用來修飾局部變量的時(shí)候,它就改變了局部變量的存儲(chǔ)位置(從原來的棧中存放改為靜態(tài)存儲(chǔ)區(qū))及其生命周期(局部靜態(tài)變量在離開作用域之后,并沒有被銷毀,而是仍然駐留在內(nèi)存當(dāng)中,直到程序結(jié)束,只不過我們不能再對(duì)他進(jìn)行訪問),但未改變其作用域。

2.全局變量

在全局變量之前加上關(guān)鍵字static,全局變量就被定義成為一個(gè)全局靜態(tài)變量。

1)內(nèi)存中的位置:靜態(tài)存儲(chǔ)區(qū)(靜態(tài)存儲(chǔ)區(qū)在整個(gè)程序運(yùn)行期間都存在)

2)初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被程序自動(dòng)初始化為0(自動(dòng)對(duì)象的值是任意的,除非他被顯示初始化)

3)作用域:全局靜態(tài)變量在聲明他的文件之外是不可見的。準(zhǔn)確地講從定義之處開始到文件結(jié)尾。

注:static修飾全局變量,并為改變其存儲(chǔ)位置及生命周期,而是改變了其作用域,使當(dāng)前文件外的源文件無法訪問該變量,好處如下:(1)不會(huì)被其他文件所訪問,修改(2)其他文件中可以使用相同名字的變量,不會(huì)發(fā)生沖突。對(duì)全局函數(shù)也是有隱藏作用。

對(duì)類中的

    1.成員變量

    用static修飾類的數(shù)據(jù)成員實(shí)際使其成為類的全局變量,會(huì)被類的所有對(duì)象共享,包括派生類的對(duì)象。因此,static成員必須在類外進(jìn)行初始化(初始化格式: int base::var=10;),而不能在構(gòu)造函數(shù)內(nèi)進(jìn)行初始化,不過也可以用const修飾static數(shù)據(jù)成員在類內(nèi)初始化 。

    特點(diǎn):

不要試圖在頭文件中定義(初始化)靜態(tài)數(shù)據(jù)成員。在大多數(shù)的情況下,這樣做會(huì)引起重復(fù)定義這樣的錯(cuò)誤。即使加上#ifndef #define #endif或者#pragma once也不行。 靜態(tài)數(shù)據(jù)成員可以成為成員函數(shù)的可選參數(shù),而普通數(shù)據(jù)成員則不可以。靜態(tài)數(shù)據(jù)成員的類型可以是所屬類的類型,而普通數(shù)據(jù)成員則不可以。普通數(shù)據(jù)成員的只能聲明為 所屬類類型的指針或引用。

2.成員函數(shù)

用static修飾成員函數(shù),使這個(gè)類只存在這一份函數(shù),所有對(duì)象共享該函數(shù),不含this指針。靜態(tài)成員是可以獨(dú)立訪問的,也就是說,無須創(chuàng)建任何對(duì)象實(shí)例就可以訪問。base::func(5,3);當(dāng)static成員函數(shù)在類外定義時(shí)不需要加static修飾符。在靜態(tài)成員函數(shù)的實(shí)現(xiàn)中不能直接引用類中說明的非靜態(tài)成員,可以引用類中說明的靜態(tài)成員。因?yàn)殪o態(tài)成員函數(shù)不含this指針。 

不可以同時(shí)用const和static修飾成員函數(shù)。

C++編譯器在實(shí)現(xiàn)const的成員函數(shù)的時(shí)候?yàn)榱舜_保該函數(shù)不能修改類的實(shí)例的狀態(tài),會(huì)在函數(shù)中添加一個(gè)隱式的參數(shù)const this*。但當(dāng)一個(gè)成員為static的時(shí)候,該函數(shù)是沒有this指針的。也就是說此時(shí)const的用法和static是沖突的。

我們也可以這樣理解:兩者的語意是矛盾的。static的作用是表示該函數(shù)只作用在類型的靜態(tài)變量上,與類的實(shí)例沒有關(guān)系;而const的作用是確保函數(shù)不能修改類的實(shí)例的狀態(tài),與類型的靜態(tài)變量沒有關(guān)系。因此不能同時(shí)用它們。

const的作用:

 1.限定變量為不可修改。

2.限定成員函數(shù)不可以修改任何數(shù)據(jù)成員。

3.const與指針:

const char *p 表示 指向的內(nèi)容不能改變。

char * const p,就是將P聲明為常指針,它的地址不能改變,是固定的,但是它的內(nèi)容可以改變。


 

 3.指針和引用的區(qū)別,引用可以用常指針實(shí)現(xiàn)嗎。

本質(zhì)上的區(qū)別是,指針是一個(gè)新的變量,只是這個(gè)變量存儲(chǔ)的是另一個(gè)變量的地址,我們通過訪問這個(gè)地址來修改變量。

而引用只是一個(gè)別名,還是變量本身。對(duì)引用進(jìn)行的任何操作就是對(duì)變量本身進(jìn)行操作,因此以達(dá)到修改變量的目的。

復(fù)制代碼
(1)指針:指針是一個(gè)變量,只不過這個(gè)變量存儲(chǔ)的是一個(gè)地址,指向內(nèi)存的一個(gè)存儲(chǔ)單元;而引用跟原來的變量實(shí)質(zhì)上是同一個(gè)東西,只不過是原變量的一個(gè)別名而已。如:int a=1;int *p=&a;int a=1;int &b=a;上面定義了一個(gè)整形變量和一個(gè)指針變量p,該指針變量指向a的存儲(chǔ)單元,即p的值是a存儲(chǔ)單元的地址。而下面2句定義了一個(gè)整形變量a和這個(gè)整形a的引用b,事實(shí)上a和b是同一個(gè)東西,在內(nèi)存占有同一個(gè)存儲(chǔ)單元。(2)可以有const指針,但是沒有const引用;(3)指針可以有多級(jí),但是引用只能是一級(jí)(int **p;合法 而 int &&a是不合法的)(4)指針的值可以為,但是引用的值不能為NULL,并且引用在定義的時(shí)候必須初始化;(5)指針的值在初始化后可以改變,即指向其它的存儲(chǔ)單元,而引用在進(jìn)行初始化后就不會(huì)再改變了。(6)"sizeof引用"得到的是所指向的變量(對(duì)象)的大小,而"sizeof指針"得到的是指針本身的大小;(7)指針和引用的自增(++)運(yùn)算意義不一樣;復(fù)制代碼
指針傳參的時(shí)候,還是值傳遞,試圖修改傳進(jìn)來的指針的值是不可以的。只能修改地址所保存變量的值。引用傳參的時(shí)候,傳進(jìn)來的就是變量本身,因此可以被修改。

4.什么是多態(tài),多態(tài)有什么用途。

定義:“一個(gè)接口,多種方法”,程序在運(yùn)行時(shí)才決定調(diào)用的函數(shù)。實(shí)現(xiàn):C++多態(tài)性主要是通過虛函數(shù)實(shí)現(xiàn)的,虛函數(shù)允許子類重寫override(注意和overload的區(qū)別,overload是重載,是允許同名函數(shù)的表現(xiàn),這些函數(shù)參數(shù)列表/類型不同)。
多態(tài)與非多態(tài)的實(shí)質(zhì)區(qū)別就是函數(shù)地址是早綁定還是晚綁定。如果函數(shù)的調(diào)用,在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并生產(chǎn)代碼,是靜態(tài)的,就是說地址是早綁定的。而如果函數(shù)調(diào)用的地址不能在編譯器期間確定,需要在運(yùn)行時(shí)才確定,這就屬于晚綁定。

3.目的:接口重用。封裝可以使得代碼模塊化,繼承可以擴(kuò)展已存在的代碼,他們的目的都是為了代碼重用。而多態(tài)的目的則是為了接口重用。

4.用法:聲明基類的指針,利用該指針指向任意一個(gè)子類對(duì)象,調(diào)用相應(yīng)的虛函數(shù),可以根據(jù)指向的子類的不同而實(shí)現(xiàn)不同的方法。

補(bǔ)充一下關(guān)于重載、重寫、隱藏(總是不記得)的區(qū)別:

復(fù)制代碼
Overload(重載):在C++程序中,可以將語義、功能相似的幾個(gè)函數(shù)用同一個(gè)名字表示,但參數(shù)或返回值不同(包括類型、順序不同),即函數(shù)重載。(1)相同的范圍(在同一個(gè)類中);(2)函數(shù)名字相同;(3)參數(shù)不同;(4)virtual 關(guān)鍵字可有可無。Override(覆蓋):是指派生類函數(shù)覆蓋基類函數(shù),特征是:(1)不同的范圍(分別位于派生類與基類);(2)函數(shù)名字相同;(3)參數(shù)相同;(4)基類函數(shù)必須有virtual 關(guān)鍵字。注:重寫基類虛函數(shù)的時(shí)候,會(huì)自動(dòng)轉(zhuǎn)換這個(gè)函數(shù)為virtual函數(shù),不管有沒有加virtual,因此重寫的時(shí)候不加virtual也是可以的,不過為了易讀性,還是加上比較好。Overwrite(重寫):隱藏,是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:(1)如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。(2)如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual關(guān)鍵字。此時(shí),基類的函數(shù)被隱藏(注意別與覆蓋混淆)。復(fù)制代碼

補(bǔ)充一下虛函數(shù)表:

多態(tài)是由虛函數(shù)實(shí)現(xiàn)的,而虛函數(shù)主要是通過虛函數(shù)表(V-Table)來實(shí)現(xiàn)的。

如果一個(gè)類中包含虛函數(shù)(virtual修飾的函數(shù)),那么這個(gè)類就會(huì)包含一張?zhí)摵瘮?shù)表,虛函數(shù)表存儲(chǔ)的每一項(xiàng)是一個(gè)虛函數(shù)的地址。如下圖:

這個(gè)類的每一個(gè)對(duì)象都會(huì)包含一個(gè)虛指針(虛指針存在于對(duì)象實(shí)例地址的最前面,保證虛函數(shù)表有最高的性能),這個(gè)虛指針指向虛函數(shù)表。

注:對(duì)象不包含虛函數(shù)表,只有虛指針,類才包含虛函數(shù)表,派生類會(huì)生成一個(gè)兼容基類的虛函數(shù)表。

原始基類的虛函數(shù)表

  下圖是原始基類的對(duì)象,可以看到虛指針在地址的最前面,指向基類的虛函數(shù)表(假設(shè)基類定義了3個(gè)虛函數(shù))

單繼承時(shí)的虛函數(shù)(無重寫基類虛函數(shù)

假設(shè)現(xiàn)在派生類繼承基類,并且重新定義了3個(gè)虛函數(shù),派生類會(huì)自己產(chǎn)生一個(gè)兼容基類虛函數(shù)表的屬于自己的虛函數(shù)表

  Derive class 繼承了 Base class 中的三個(gè)虛函數(shù),準(zhǔn)確的說,是該函數(shù)實(shí)體的地址被拷貝到 Derive類的虛函數(shù)表,派生類新增的虛函數(shù)置于虛函數(shù)表的后面,并按聲明順序存放

單繼承時(shí)的虛函數(shù)(重寫基類虛函數(shù)

現(xiàn)在派生類重寫基類的x函數(shù),可以看到這個(gè)派生類構(gòu)建自己的虛函數(shù)表的時(shí)候,修改了base::x()這一項(xiàng),指向了自己的虛函數(shù)。

多重繼承時(shí)的虛函數(shù)(Derived ::public Base1,public Base2)

這個(gè)派生類多重繼承了兩個(gè)基類base1,base2,因此它有兩個(gè)虛函數(shù)表。

  

  它的對(duì)象會(huì)有多個(gè)虛指針(據(jù)說和編譯器相關(guān)),指向不同的虛函數(shù)表。

  多重繼承時(shí)指針的調(diào)整:

Derive b;Base1* ptr1 = &b;   // 指向 b 的初始地址Base2* ptr2 = &b;   // 指向 b 的第二個(gè)子對(duì)象

因?yàn)?Base1 是第一個(gè)基類,所以 ptr1 指向的是 Derive 對(duì)象的起始地址,不需要調(diào)整指針(偏移)。

因?yàn)?Base2 是第二個(gè)基類,所以必須對(duì)指針進(jìn)行調(diào)整,即加上一個(gè) offset,讓 ptr2 指向 Base2 子對(duì)象。

當(dāng)然,上述過程是由編譯器完成的。

Base1* b1 = (Base1*)ptr2;b1->y();                   // 輸出 Base2::y()Base2* b2 = (Base2*)ptr1;b2->y();                   // 輸出 Base1::y()

其實(shí),通過某個(gè)類型的指針訪問某個(gè)成員時(shí),編譯器只是根據(jù)類型的定義查找這個(gè)成員所在偏移量,用這個(gè)偏移量獲取成員。由于 ptr2 本來就指向 Base2 子對(duì)象的起始地址,所以b1->y()調(diào)用到的是Base2::y(),而 ptr1 本來就指向 Base1 子對(duì)象的起始地址(即 Derive對(duì)象的起始地址),所以b2->y()調(diào)用到的是Base1::y()

虛繼承時(shí)的虛函數(shù)表

  虛繼承的引入把對(duì)象的模型變得十分復(fù)雜,除了每個(gè)基類(MyClassA和MyClassB)和公共基類(MyClass)的虛函數(shù)表指針需要記錄外,每個(gè)虛擬繼承了MyClass的父類還需要記錄一個(gè)虛基類表vbtable的指針vbptr。MyClassC的對(duì)象模型如圖4所示。

  

   虛基類表每項(xiàng)記錄了被繼承的虛基類子對(duì)象相對(duì)于虛基類表指針的偏移量。比如MyClassA的虛基類表第二項(xiàng)記錄值為24,正是MyClass::vfptr相對(duì)于MyClassA::vbptr的偏移量,同理MyClassB的虛基類表第二項(xiàng)記錄值12也正是MyClass::vfptr相對(duì)于MyClassA::vbptr的偏移量。(虛函數(shù)與虛繼承深入探討)

對(duì)象模型探討:

 

1.沒有繼承情況,vptr存放在對(duì)象的開始位置,以下是Base1的內(nèi)存布局

m_iData :100

 2.單繼承的情況下,對(duì)象只有一個(gè)vptr,它存放在對(duì)象的開始位置,派生類子對(duì)象在父類子對(duì)象的最后面,以下是D1的內(nèi)存布局

B1:: m_iData : 100

B1::vptr : 4294800

B2::vptr : 4294776

D::m_iData :300

4. 虛擬繼承情況下,虛父類子對(duì)象會(huì)放在派生類子對(duì)象之后,派生類子對(duì)象的第一個(gè)位置存放著一個(gè)vptr,虛擬子類子對(duì)象也會(huì)保存一個(gè)vptr,以下是VD1的內(nèi)存布局

 

 Unknown : 4294888

B1::vptr :4294864

VD1::vptr :        4294944

VD1::m_iData :  200

VD2::Unknown : 4294952

VD::m_iData : 500

B1::m_iData :  100

5. 棱形繼承的情況下,非虛基類子對(duì)象在派生類子對(duì)象前面,并按照聲明順序排列,虛基類子對(duì)象在派生類子對(duì)象后面

VD1::Unknown : 4294968

VD2::vptr :    4   294932

VD2::m_iData : 300

B1::vptr :       4294920

B1::m_iData :  100

 

補(bǔ)充一下純虛函數(shù):

定義: 在很多情況下,基類本身生成對(duì)象是不合情理的。為了解決這個(gè)問題,方便使用類的多態(tài)性,引入了純虛函數(shù)的概念,將函數(shù)定義為純虛函數(shù)(方法:virtual ReturnType Function()= 0;)純虛函數(shù)不能再在基類中實(shí)現(xiàn),編譯器要求在派生類中必須予以重寫以實(shí)現(xiàn)多態(tài)性。同時(shí)含有純虛擬函數(shù)的類稱為抽象類,它不能生成對(duì)象。特點(diǎn):

1,當(dāng)想在基類中抽象出一個(gè)方法,且該基類只做能被繼承,而不能被實(shí)例化;(避免類被實(shí)例化且在編譯時(shí)候被發(fā)現(xiàn),可以采用此方法)

2,這個(gè)方法必須在派生類(derived class)中被實(shí)現(xiàn);

目的:使派生類僅僅只是繼承函數(shù)的接口。補(bǔ)充一下純虛函數(shù):定義:稱帶有純虛函數(shù)的類為抽象類。作用:為一個(gè)繼承體系提供一個(gè)公共的根,為派生類提供操作接口的通用語義。特點(diǎn):1.抽象類只能作為基類來使用,而繼承了抽象類的派生類如果沒有實(shí)現(xiàn)純虛函數(shù),而只是繼承純虛函數(shù),那么該類仍舊是一個(gè)抽象類,如果實(shí)現(xiàn)了純虛函數(shù),就不再是抽象類。      2.抽象類不可以定義對(duì)象。補(bǔ)充一下多重繼承和虛繼承:多重繼承:定義:派生類繼承多個(gè)基類,派生類為每個(gè)基類(顯式或隱式地)指定了訪問級(jí)別——publicprotected 或 private
    class Panda : public Bear, public Endangered {    }

構(gòu)造:

派生類的對(duì)象包含每個(gè)基類的基類子對(duì)象。派生類構(gòu)造函數(shù)初始化所有基類(多重繼承中若沒有顯式調(diào)用某個(gè)基類的構(gòu)造函數(shù),則編譯器會(huì)調(diào)用該基類默認(rèn)構(gòu)造函數(shù)),派生類只能初始化自己的基類,并不需要考慮基類的基類怎么初始化。多重繼承時(shí),基類構(gòu)造函數(shù)按照基類構(gòu)造函數(shù)在類派生列表中的出現(xiàn)次序調(diào)用。析構(gòu):總是按構(gòu)造函數(shù)運(yùn)行的逆序調(diào)用析構(gòu)函數(shù)。(基類的析構(gòu)函數(shù)最好寫成virtual,否則再子類對(duì)象銷毀的時(shí)候,無法銷毀子類對(duì)象部分資源。)假定所有根基類都將它們的析構(gòu)函數(shù)適當(dāng)定義為虛函數(shù),那么,無論通過哪種指針類型刪除對(duì)象,虛析構(gòu)函數(shù)的處理都是一致的。 拷貝構(gòu)造/賦值:如果要為派生類編寫拷貝構(gòu)造函數(shù),則需要為調(diào)用基類相應(yīng)拷貝構(gòu)造函數(shù)并為其傳遞參數(shù),否則只會(huì)拷貝派生類部分。復(fù)制代碼
深拷貝與淺拷貝:淺拷貝:默認(rèn)的復(fù)制構(gòu)造函數(shù)只是完成了對(duì)象之間的位拷貝,也就是把對(duì)象里的值完全復(fù)制給另一個(gè)對(duì)象,如A=B。這時(shí),如果B中有一個(gè)成員變量指針已經(jīng)申請(qǐng)了內(nèi)存,那A中的那個(gè)成員變量也指向同一塊內(nèi)存。    這就出現(xiàn)了問題:當(dāng)B把內(nèi)存釋放了(如:析構(gòu)),這時(shí)A內(nèi)的指針就是野指針了,出現(xiàn)運(yùn)行錯(cuò)誤。深拷貝:自定義復(fù)制構(gòu)造函數(shù)需要注意,對(duì)象之間發(fā)生復(fù)制,資源重新分配,即A有5個(gè)空間,B也應(yīng)該有5個(gè)空間,而不是指向A的5個(gè)空間。復(fù)制代碼

虛繼承與虛基類:

定義:在多重繼承下,一個(gè)基類可以在派生層次中出現(xiàn)多次。(派生類對(duì)象中可能出現(xiàn)多個(gè)基類對(duì)象)在 C++ 中,通過使用虛繼承解決這類問題。虛繼承是一種機(jī)制,類通過虛繼承指出它希望共享其虛基類的狀態(tài)。在虛繼承下,對(duì)給定虛基類,無論該類在派生層次中作為虛基類出現(xiàn)多少次,只繼承一個(gè)共享的基類子對(duì)象。共享的基類子對(duì)象稱為虛基類

用法:istream 和 ostream 類對(duì)它們的基類進(jìn)行虛繼承。通過使基類成為虛基類,istream 和 ostream 指定,如果其他類(如 iostream 同時(shí)繼承它們兩個(gè),則派生類中只出現(xiàn)它們的公共基類ios的一個(gè)副本。通過在派生列表中包含關(guān)鍵字 virtual 設(shè)置虛基類:
    class istream : public virtual ios { ... };    class ostream : virtual public ios { ... };    // iostream inherits only one copy of its ios base class    class iostream: public istream, public ostream { ... };
5.各個(gè)排序算法的時(shí)間復(fù)雜度和穩(wěn)定性,快排的原理。

排序深入探討

插入排序

  每次將一個(gè)待排序的數(shù)據(jù),跟前面已經(jīng)有序的序列的數(shù)字一一比較找到自己合適的位置,插入到序列中,直到全部數(shù)據(jù)插入完成。

希爾排序

  先將整個(gè)待排元素序列分割成若干個(gè)子序列(由相隔某個(gè)“增量”的元素組成的)分別進(jìn)行直接插入排序,然后依次縮減增量再進(jìn)行排序,待整個(gè)序列中的元素基本有序(增量足夠小)時(shí),再對(duì)全體元素進(jìn)行一次直接插入排序。由于希爾排序是對(duì)相隔若干距離的數(shù)據(jù)進(jìn)行直接插入排序,因此可以形象的稱希爾排序?yàn)椤?strong>跳著插”

冒泡排序

通過交換使相鄰的兩個(gè)數(shù)變成小數(shù)在前大數(shù)在后,這樣每次遍歷后,最大的數(shù)就“沉”到最后面了。重復(fù)N次即可以使數(shù)組有序。

冒泡排序改進(jìn)1:在某次遍歷中如果沒有數(shù)據(jù)交換,說明整個(gè)數(shù)組已經(jīng)有序。因此通過設(shè)置標(biāo)志位來記錄此次遍歷有無數(shù)據(jù)交換就可以判斷是否要繼續(xù)循環(huán)。

冒泡排序改進(jìn)2:記錄某次遍歷時(shí)最后發(fā)生數(shù)據(jù)交換的位置,這個(gè)位置之后的數(shù)據(jù)顯然已經(jīng)有序了。因此通過記錄最后發(fā)生數(shù)據(jù)交換的位置就可以確定下次循環(huán)的范圍了。

快速排序

“挖坑填數(shù)+分治法”,首先令i =L; j = R; 將a[i]挖出形成第一個(gè)坑,稱a[i]為基準(zhǔn)數(shù)。然后j--由后向前找比基準(zhǔn)數(shù)小的數(shù),找到后挖出此數(shù)填入前一個(gè)坑a[i]中,再i++由前向后找比基準(zhǔn)數(shù)大的數(shù),找到后也挖出此數(shù)填到前一個(gè)坑a[j]中。重復(fù)進(jìn)行這種“挖坑填數(shù)”直到i==j。再將基準(zhǔn)數(shù)填入a[i]中,這樣i之前的數(shù)都比基準(zhǔn)數(shù)小,i之后的數(shù)都比基準(zhǔn)數(shù)大。因此將數(shù)組分成二部分再分別重復(fù)上述步驟就完成了排序。

選擇排序

數(shù)組分成有序區(qū)和無序區(qū),初始時(shí)整個(gè)數(shù)組都是無序區(qū),然后每次從無序區(qū)選一個(gè)最小的元素直接放到有序區(qū)的最后,直到整個(gè)數(shù)組變有序區(qū)。

堆排序

堆的插入就是——每次插入都是將新數(shù)據(jù)放在數(shù)組最后,而從這個(gè)新數(shù)據(jù)的父結(jié)點(diǎn)到根結(jié)點(diǎn)必定是一個(gè)有序的數(shù)列,因此只要將這個(gè)新數(shù)據(jù)插入到這個(gè)有序數(shù)列中即可。

堆的刪除就是——堆的刪除就是將最后一個(gè)數(shù)據(jù)的值賦給根結(jié)點(diǎn),然后再?gòu)母Y(jié)點(diǎn)開始進(jìn)行一次從上向下的調(diào)整。調(diào)整時(shí)先在左右兒子結(jié)點(diǎn)中找最小的,如果父結(jié)點(diǎn)比這個(gè)最小的子結(jié)點(diǎn)還小說明不需要調(diào)整了,反之將父結(jié)點(diǎn)和它交換后再考慮后面的結(jié)點(diǎn)。相當(dāng)于從根結(jié)點(diǎn)開始將一個(gè)數(shù)據(jù)在有序數(shù)列中進(jìn)行“下沉”。

因此,堆的插入和刪除非常類似直接插入排序,只不是在二叉樹上進(jìn)行插入過程。所以可以將堆排序形容為“樹上插

歸并排序

歸并排序主要分為兩步:分?jǐn)?shù)列(divide),每次把數(shù)列一分為二,然后分到只有兩個(gè)元素的小數(shù)列;合數(shù)列(Merge),合并兩個(gè)已經(jīng)內(nèi)部有序的子序列,直至所有數(shù)字有序。用遞歸可以實(shí)現(xiàn)。

基數(shù)排序(桶排序)

基數(shù)排序,第一步根據(jù)數(shù)字的個(gè)位分配到每個(gè)桶里,在桶內(nèi)部排序,然后將數(shù)字再輸出(串起來);然后根據(jù)十位分桶,繼續(xù)排序,再串起來。直至所有位被比較完,所有數(shù)字已經(jīng)有序。

   


 

6.vector中size()和capacity()的區(qū)別。

 

size()指容器當(dāng)前擁有的元素個(gè)數(shù)(對(duì)應(yīng)的resize(size_type)會(huì)在容器尾添加或刪除一些元素,來調(diào)整容器中實(shí)際的內(nèi)容,使容器達(dá)到指定的大小。);capacity()指容器在必須分配存儲(chǔ)空間之前可以存儲(chǔ)的元素總數(shù)。

 

size表示的這個(gè)vector里容納了多少個(gè)元素,capacity表示vector能夠容納多少元素,它們的不同是在于vector的size是2倍增長(zhǎng)的。如果vector的大小不夠了,比如現(xiàn)在的capacity是4,插入到第五個(gè)元素的時(shí)候,發(fā)現(xiàn)不夠了,此時(shí)會(huì)給他重新分配8個(gè)空間,把原來的數(shù)據(jù)及新的數(shù)據(jù)復(fù)制到這個(gè)新分配的空間里。(會(huì)有迭代器失效的問題)

各容器的特點(diǎn):

 


7.map和set的原理。

(map和set的四個(gè)問題)

map和set的底層實(shí)現(xiàn)主要是由紅黑樹實(shí)現(xiàn)的。

紅黑樹:

性質(zhì)1 節(jié)點(diǎn)是紅色黑色。性質(zhì)2 根節(jié)點(diǎn)是黑色。性質(zhì)3 每個(gè)葉節(jié)點(diǎn)(NIL節(jié)點(diǎn),空節(jié)點(diǎn))是黑色的。性質(zhì)4 每個(gè)紅色節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)都是黑色。(從每個(gè)葉子到根的所有路徑上不能有兩個(gè)連續(xù)的紅色節(jié)點(diǎn))性質(zhì)5 從任一節(jié)點(diǎn)到其每個(gè)葉子的所有路徑都包含相同數(shù)目的黑色節(jié)點(diǎn)。這些約束的好處是:保持了樹的相對(duì)平衡,同時(shí)又比AVL的插入刪除操作的復(fù)雜性要低許多。

(深入探討紅黑樹)


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 屯门区| 睢宁县| 巴彦淖尔市| 青川县| 敦煌市| 陇南市| 宜丰县| 夏河县| 桂东县| 信丰县| 禹城市| 远安县| 凤翔县| 广州市| 增城市| 城市| 邯郸市| 内丘县| 西青区| 蕉岭县| 五台县| 金沙县| 固阳县| 陆河县| 蓬溪县| 海口市| 澜沧| 黔西| 满洲里市| 潮安县| 岳阳县| 许昌县| 彭泽县| 阳原县| 澄城县| 沾化县| 石嘴山市| 图木舒克市| 晋中市| 穆棱市| 遂宁市|