C++ 经典面试题
?1,關于動態(tài)申請內(nèi)存
答:內(nèi)存分配方式三種:
(1)從靜態(tài)存儲區(qū)域分配:內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運行期間都存在。
全局變量,static變量。
(2)在棧上創(chuàng)建:在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,
函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。
棧內(nèi)存分配運算 內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
(3)用malloc或new申請內(nèi)存之后,應該立即檢查指針值是否為NULL.防止使用指針值為NULL的內(nèi)存,
不要忘記為數(shù)組和動態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。避免數(shù)組或指針的下標越界,
特別要當心發(fā)生“多1”或者“少1”操作。動態(tài)內(nèi)存的申請與釋放必須配對,防止內(nèi)存泄漏。
用free或delete釋放了內(nèi)存之后,立即將指針設置為NULL,防止產(chǎn)生“野指針”。從堆上分配,亦稱動態(tài)內(nèi)存分配。
程序在運行的時候用malloc或new申請任意多少的內(nèi)存,程序員自己負責在何時用free或delete釋放內(nèi)存。
動態(tài)內(nèi)存的生存期由程序員決定,使用非常靈活。(int *pArray;???int MyArray[6];????pArray = &MyArray[0];)
如果在申請動態(tài)內(nèi)存時找不到足夠大的內(nèi)存塊,malloc和new將返回NULL指針,
判斷指針是否為NULL,如果是 則馬上用return語句終止本函數(shù),
或者馬上用exit(1)終止整個程序的運行,為new和malloc設置異常處理函數(shù)。
?
2,C++指針攻破
答案:指針是一個變量,專門存放內(nèi)存地址,特點是能訪問所指向的內(nèi)存
?* 指針取內(nèi)容 ?&引用取地址
?指針本身占據(jù)了4個字節(jié)的長度 ?
int **ptr; ? ?//指針的類型是 int ** ? ? ? ??他是一個指針,指向另一個指針
int (*ptr)[3]; //指針的類型是 int(*)[3] ? ? ? ?他是一個指針,指向一個有三個int元素的數(shù)組
int *(*ptr)[4]; //指針的類型是 int *(*)[4] ? ? ?他是一個指針,指向一個數(shù)組,數(shù)組里放著4個指
【】的優(yōu)先級大于指針*
針類型的元素
?ptr++:指針ptr的值加上了sizeof(int)
ptr+=5:將指針ptr的值加上5*sizeof(int)
指針數(shù)組:就是一個由指針組成的數(shù)組,那個數(shù)組的各個元素都是指針,指向某個內(nèi)存地址?!har *p[10];//p是一個指針數(shù)組
?數(shù)組指針:數(shù)組名本身就是一個指針,指向數(shù)組的首地址。注意這是一個常數(shù)。 ? ??char (*p)[10] //p是一個數(shù)組指針
?函數(shù)指針:本身是一個指針,指向一個函數(shù)入口地址,通過該指針可調(diào)用其指向的函數(shù),使用函數(shù)指針可實現(xiàn)回調(diào)函數(shù)。
int func(int x); /* 聲明一個函數(shù) */
int (*f) (int x); /* 聲明一個函數(shù)指針 */
f=func; /* 將func函數(shù)的首地址賦給指針f */
或者使用下面的方法將函數(shù)地址賦給函數(shù)指針:
f = &func;
賦值時函數(shù)func不帶括號,也不帶參數(shù),由于func代表函數(shù)的首地址,因此經(jīng)過賦值以后,指針f就指向函數(shù)func(x)的代碼的首地址。
指針函數(shù):本身是一個函數(shù),其返回值是一個指針。?void * fun(void);// fun是一個指針函數(shù)
?
?常量指針;他是一個指針,指向一個常量。?const int *p; 或?int const *p;
? ? ??注意?指針指向的對象不能通過這個指針來修改,可是仍然可以通過原來的聲明修改,也就是說常量指針可以被賦值為變量的地 ? ? ? ??址, ? ??之所 ??以叫做常量指針,是限制了通過這個指針修改變量的值。?
? ? ? ?int a = 5;
? ? ??const int b = 8;
? ????const int *c = &a; // 這是合法的,非法的是對c的使用
??????*c = 6; // 非法,但可以這樣修改c指向的對象的值:a = 6;
? ? ?const int *d = &b; // b是常量,d可以指向b,d被賦值為b的地址是合法的
????? 細心的朋友在使用字符串處理函數(shù)的時候,應該會注意到這些函數(shù)的聲明。它們的參數(shù)一般聲明為常量指針。例如,字符串比較函數(shù) ? ? ??的聲明是這樣的: ?str1和str2的內(nèi)容顯然是可以更改的,函數(shù)的參數(shù)聲明用了常量指針的形式,就保證了在函數(shù)內(nèi)部,那 個常量不 ? ? ??被更改。也就是說,對str1和str2的內(nèi)容更改的操作在函數(shù)內(nèi)部是不被允許的。這就是作用所在?(就目前的應用來看,我覺得 ? ? ??設置常量指針就是為函數(shù)參數(shù)聲明準 備的,不然還真不知道用在什么地方呢,呵呵!)
? ? ??int strcmp(const char *str1, const char *str2);
? ? ?雖然常量指針指向的對象不能變化,可是因為常量指針是一個變量,因此,常量指針可以不被賦初始值,且可以被重新賦值。?
? ? ?const int a = 12;???const int b = 15;?const int *c = &a; ?const int *d;?
? ???d = &a; // 這樣當然是可以的 ? ? ? ? ? ? ? ? ? ? ? ? ?c = &b; // 雖然c已經(jīng)被賦予初始值,可是仍然可以指向另一個變量
指針常量?;?int a;?int *const b = &a; //const放在指針聲明操作符的右側(cè) ? ??指針是常量?b的值是一個常量 b的值是a的地址,但 ? ? ? ? ? ? ? ?是a地址里面的人可以換
指針的賦值:
把一個變量的地址 賦予指向 相同數(shù)據(jù)類型的指針變量( int a;???int *ip;???ip=&a; )
把一個指針變量的值 賦予指向相同類型 變量的另一個指針變量(int a;??int *pa=&a;??int *pb;???pb=pa; )
把數(shù)組的首地址賦予指向數(shù)組的指針變量(int a[5],*pa;??pa=a;???也可寫為:pa=&a[0];)
?
如果給指針加1或減1 ,實際上是加上或減去指針所指向的數(shù)據(jù)類型所占空間的大小。
當給指針加上一個整數(shù)值或減去一個整數(shù)值時,表達式返回一個新地址。
相同類型的兩個指針可以相減,減后返回的整數(shù)代表兩個地址間該類型的實例個數(shù)。
?
int ** cc=new (int*)[10]; ?聲明一個10個元素的數(shù)組,數(shù)組每個元素都是一個int *指針,
每個元素還可以單獨申請空間,因為cc的類型是int*型的指針,所以你要在堆里申請的話就要用int *來申請;
???int ** a= new int * [2]; //申請兩個int * 型的空間
???a[0] = new int[4]; 為a的第一個元素申請了4個int 型空間,a[0] 指向了此空間的首地址處
???a[1] = new int[3]; //為a的第二個元素又申請了3個int 型空間,a[1]指向了此空間首地址處
?
指針數(shù)組初始化賦值:
void *malloc(int size);
說明:malloc 向系統(tǒng)申請分配指定size個字節(jié)的內(nèi)存空間。返回類型是?void*?類型。void* 表示未確定類型的指針。C,C++規(guī)定,void* 類型可以強制轉(zhuǎn)換為任何其它類型的指針。??
一維指針開辟空間:char *str; ??int *arr;????scanf("%d",&N);
str=(char*)malloc(sizeof(char)*N);
arr=(int*)malloc(sizeof(int)*N);
二維指針開辟空間:int **arr, ? ? i; ? ? ? ? scanf("%d%d",&row,&col);
arr=(int**)malloc(sizeof(int)*row);
for(i=0;i<row;i++)
???arr[i]=(int*)malloc(sizeof(int)*col);
?
結(jié)構(gòu)體指針數(shù)組,例如typedef struct{???char x;???int??y; }Quan,*QQuan;
定義一個結(jié)構(gòu)體指針數(shù)組如:QQuan a[MAX]?
for(i=0;i<MAX;i++)
{
????a[i]=(QQuan)malloc(sizeof(Quan));
????memset(a[i],0,sizeof(Quan));
}
指針數(shù)組賦值
?float a[]={100,200,300,400,500};
float??*p[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
?
?
char *units[1000];
char get_unit[250];???????????????????????????????????????????????????????????????????????????
for(int i=0;i<get_unit_num;i++){ units[i]=(char*) malloc(60*sizeof(char*));?
scanf("%s", get_unit);???strcpy(units[i],get_unit);}
?
?
3,復雜指針解析:
(1)int (*func)(int *p);?首先是一個指針,指向一個函數(shù),這類函數(shù)具有int*類型的形參,返回值類型是 int。
(*func)()是一個函數(shù),func是一個指向這類函數(shù)的指針,就是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值類型是 int。
(2)int (*func)(int *p, int (*f)(int*));
func是一個指向函數(shù)的指針,這類函數(shù)具有int *和int (*)(int*)這樣的形參。形參int (*f)(int*),f也是一個函數(shù)指針
(3)int (*func[5])(int *p);?func是一個數(shù)組,里面是一個個指針,指向函數(shù)。
func數(shù)組的元素是函數(shù)指針,它所指向的函數(shù)具有int*類型的形參,返回值類型為int。
(4)int (*(*func)[5])(int *p);?func是一個指針,指向五個元素的數(shù)組,什么元素呢?指針元素,指向函數(shù)的指針元素。
func是一個指向數(shù)組的指針,這個數(shù)組的元素是函數(shù)指針,這些指針指向具有int*形參,返回值為int類型的函數(shù)。
(5)int (*(*func)(int *p))[5];?
func是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值是指向數(shù)組的指針,所指向的數(shù)組的元素是具有5個int元素的數(shù)組。
注意:
需要聲明一個復雜指針時,如果把整個聲明寫成上面所示的形式,對程序可讀性是一大損害。
應該用typedef來對聲明逐層,分解,增強可讀性,例如對于聲明:int (*(*func)(int *p))[5];
這樣分解:typedef??int (*PARA)[5];????typedef PARA (*func)(int *);
?
例如:int (*(*func)[5][6])[7][8];?func 是一個指針,指向5X6的數(shù)組,數(shù)組里面裝的是指針,指向7X8int元素的數(shù)組。
func是一個指向數(shù)組的指針,這類數(shù)組的元素是一個具有5X6個int元素的二維數(shù)組,而這個二維數(shù)組的元素又是一個二維數(shù)組。
typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];
4,函數(shù)指針詳解
答:
函數(shù)指針是指向一個函數(shù)入口的指針
一個函數(shù)指針只能指向一種類型的函數(shù),即具有相同的返回值和相同的參數(shù)的函數(shù)。
函數(shù)指針數(shù)組定義:void(*fun[3])(void*);??相應指向類A的成員函數(shù)的指針:void (A::*pmf)(char *, const char *);
指向外部函數(shù)的指針:void (*pf)(char *, const char *); void strcpy(char * dest, const char * source); pf=strcpy;
?
?
5,野指針
答:“野指針”是很危險的,if語句對它不起作用。“野指針”的成因主要有兩種:
(1)指針變量沒有被初始化。指針變量在創(chuàng)建的同時應當被初始化,要么將指針設置為NULL,要么讓它指向合法的內(nèi)存。
char *p = NULL;??????char *str = (char *) malloc(100);
(2)指針p被free或者delete之后,沒有置為NULL
(3)指針操作超越了變量的作用范圍。所指向的內(nèi)存值對象生命期已經(jīng)被銷毀
?
6,引用和指針有什么區(qū)別?
答:引用必須初始化,指針則不必;引用初始化以后不能改變,指針可以改變其指向的對象;
不存在指向空值的引用,但存在指向控制的指針;
引用是某個對象的別名,主要用來描述函數(shù)和參數(shù)和返回值。而指針與一般的變量是一樣的,會在內(nèi)存中開辟一塊內(nèi)存。
如果函數(shù)的參數(shù)或返回值是類的對象的話,采用引用可以提高程序的效率。
?
7,C++中的Const用法
答:char * const p;????// 指針不可改,也就說指針只能指向一個地址,不能更改為其他地址,修飾指針本身
char const * p;???// 所指內(nèi)容不可改,也就是說*p是常量字符串,修飾指針所指向的變量
const char * const p 和 char const * const p; // 內(nèi)容和指針都不能改
?
const修飾函數(shù)參數(shù)是它最廣泛的一種用途,它表示函數(shù)體中不能修改參數(shù)的值,
傳遞過來的參數(shù)在函數(shù)內(nèi)不可以改變,參數(shù)指針所指內(nèi)容為常量不可變,參數(shù)指針本身為常量不可變
在引用或者指針參數(shù)的時候使用const限制是有意義的,而對于值傳遞的參數(shù)使用const則沒有意義
?
const修飾類對象表示該對象為常量對象,其中的任何成員都不能被修改。
const修飾的對象,該對象的任何非const成員函數(shù)都不能被調(diào)用,因為任何非const成員函數(shù)會有修改成員變量的企圖。
const修飾類的成員變量,表示成員常量,不能被修改,同時它只能在初始化列表中賦值。static const 的成員需在聲明的地方直接初始。
const修飾類的成員函數(shù),則該成員函數(shù)不能修改類中任何非const成員。一般寫在函數(shù)的最后來修飾。
在函數(shù)實現(xiàn)部分也要帶const關鍵字.
對于const類對象/指針/引用,只能調(diào)用類的const成員函數(shù),因此,const修飾成員函數(shù)的最重要作用就是限制對于const對象的使用
?
使用const的一些建議:在參數(shù)中使用const應該使用引用或指針,而不是一般的對象實例
const在成員函數(shù)中的三種用法(參數(shù)、返回值、函數(shù))要很好的使用;
const在成員函數(shù)中的三種用法(參數(shù)、返回值、函數(shù))要很好的使用;
不要輕易的將函數(shù)的返回值類型定為const;除了重載操作符外一般不要將返回值類型定為對某個對象的const引用;
?
8,const常量與define宏定義的區(qū)別
答:(1)?編譯器處理方式不同。define宏是在預處理階段展開,生命周期止于編譯期。
只是一個常數(shù)、一個命令中的參數(shù),沒有實際的存在。
#define常量存在于程序的代碼段。const常量是編譯運行階段使用,const常量存在于程序的數(shù)據(jù)段.
?
(2)類型和安全檢查不同。define宏沒有類型,不做任何類型檢查,僅僅是展開。
const常量有具體的類型,在編譯階段會執(zhí)行類型檢查。
(3)?存儲方式不同。define宏僅僅是展開,有多少地方使用,就展開多少次,不會分配內(nèi)存。
const常量會在內(nèi)存中分配(可以是堆中也可以是棧中)
?
9,解釋堆和棧的區(qū)別
答:1、棧區(qū)(stack)— 由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
由系統(tǒng)自動分配。聲明在函數(shù)中一個局部變量 int b; 系統(tǒng)自動在棧中為b開辟空間 。
只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出。
在Windows下,棧是向低地址擴展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域,棧的大小是2M。
如果申請的空間超過棧的剩余空間時,將提示overflow。
棧由系統(tǒng)自動分配,速度較快。但程序員是無法控制的。
函數(shù)調(diào)用時,第一個進棧的是主函數(shù)中后的下一條指令,的地址,然后是函數(shù)的各個參數(shù)。
在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。
?
堆區(qū)(heap) — 一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由OS回收 。
注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表,需要程序員自己申請,并指明大小,在c中malloc函數(shù)
在C++中用new運算符。首先應該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當系統(tǒng)收到程序的申請時,
另外,由于找到的堆結(jié)點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。
堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。而鏈表的遍歷方向是由低地址向高地址。
堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。
堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便
一般是在堆的頭部用一個字節(jié)存放堆的大小。
?
10,論述含參數(shù)的宏和函數(shù)的優(yōu)缺點
(1)函數(shù)調(diào)用時,先求出實參表達式的值,然后代入形參。而使用帶參的宏只是進行簡單的字符替換
(2)函數(shù)調(diào)用是在程序運行時處理的,分配臨時的內(nèi)存單元;而宏展開是在編譯時進行的,在展開時不進行
內(nèi)存分配,不進行值得傳遞處理,沒有“返回值”概念
(3)對函數(shù)中的形參和實參都要定義類型,類型要求一致,如不一致則進行類型轉(zhuǎn)換。而宏不存在類型問題
(4)調(diào)用函數(shù)只可得到一個返回值,而用宏則可以設法得到幾個結(jié)果
(5)實用宏次數(shù)多時,宏展開后源程序變長,沒展開一次源程序增長,函數(shù)調(diào)用則不會
(6)宏替換不占用運行時間,只占編譯時間,而函數(shù)調(diào)用占用運行時間
?
11,C++的空類,默認產(chǎn)生哪些類成員函數(shù)?
答:class Empty
{
?public:
Empty(); ??????????????????????????//缺省構(gòu)造函數(shù)
Empty(const Empty& );???????????//拷貝構(gòu)造函數(shù)
~Empty();??????????????????????????//虛構(gòu)函數(shù)
Empty& operator(const Empty& )?????//賦值運算符
Empty& operator&();???????????????//取址運算符
const Empty* operator&() const;???// 取址運算符 const
}
?
12,談談類和結(jié)構(gòu)體的區(qū)別
答:結(jié)構(gòu)體在默認情況下的成員都是public的,而類在默認情況下的成員是private的。結(jié)構(gòu)體和類都必須使用new創(chuàng)建,
struct保證成員按照聲明順序在內(nèi)存在存儲,而類不保證。
?
13,C++四種強制類型轉(zhuǎn)換
答:(1)const_cast
字面上理解就是去const屬性,去掉類型的const或volatile屬性。
struct SA{??int k};??const SA ra;???
ra.k = 10;????//直接修改const類型,編譯錯誤???SA& rb =??const_cast<SA&>(ra);???rb.k = 10; //可以修改
?
(2)static_cast
主要用于基本類型之間和具有繼承關系的類型之間的轉(zhuǎn)換。用于指針類型的轉(zhuǎn)換沒有太大的意義
static_cast是無條件和靜態(tài)類型轉(zhuǎn)換,可用于基類和子類的轉(zhuǎn)換,基本類型轉(zhuǎn)換,把空指針轉(zhuǎn)換為目標類型的空指針,
把任何類型的表達式轉(zhuǎn)換成void類型,static_cast不能進行無關類型(如非基類和子類)指針之間的轉(zhuǎn)換。
int a;?????double d = static_cast<double>(a);???//基本類型轉(zhuǎn)換
int &pn = &a;?????void *p = static_cast<void*>(pn);???//任意類型轉(zhuǎn)換為void
?
(3)dynamic_cast
?
你可以用它把一個指向基類的指針或引用對象轉(zhuǎn)換成繼承類的對象
動態(tài)類型轉(zhuǎn)換,運行時類型安全檢查(轉(zhuǎn)換失敗返回NULL)
基類必須有虛函數(shù),保持多態(tài)特性才能用dynamic_cast
只能在繼承類對象的指針之間或引用之間進行類型轉(zhuǎn)換
class BaseClass{public:??int m_iNum;??virtual void foo(){};};
class DerivedClass:BaseClass{public: char* szName[100];??void bar(){};};
BaseClass* pb = new DerivedClass();
?
DerivedClass *p2 = dynamic_cast<DerivedClass *>(pb);
BaseClass* pParent = dynamic_cast<BaseClass*>(p2);
//子類->父類,動態(tài)類型轉(zhuǎn)換,正確
?
(4)reinterpreter_cast
轉(zhuǎn)換的類型必須是一個指針、引用、算術類型、函數(shù)指針或者成員指針。
主要是將一個類型的指針,轉(zhuǎn)換為另一個類型的指針
不同類型的指針類型轉(zhuǎn)換用reinterpreter_cast
最普通的用途就是在函數(shù)指針類型之間進行轉(zhuǎn)換
int DoSomething(){return 0;};
typedef void(*FuncPtr)(){};
FuncPtr funcPtrArray[10];
funcPtrArray[0] = reinterpreter_cast<FuncPtr>(&DoSomething);
?
14,C++函數(shù)中值的傳遞方式有哪幾種?
答:函數(shù)的三種傳遞方式為:值傳遞、指針傳遞和引用傳遞。
?
15,將“引用”作為函數(shù)參數(shù)有哪些特點
答:(1)傳遞引用給函數(shù)與傳遞指針的效果是一樣的,這時,被調(diào)函數(shù)的形參就成為原來主調(diào)函數(shù)的實參變量或者
對象的一個別名來使用,所以在被調(diào)函數(shù)中形參的操作就是對相應的目標對象的操作
(2)使用引用傳遞函數(shù)的參數(shù),在內(nèi)存中并沒有產(chǎn)生實參的副本,它是直接對實參操作,當參數(shù)數(shù)據(jù)較大時,引用
傳遞參數(shù)的效率和所占空間都好
(3)如果使用指針要分配內(nèi)存單元,需要重復使用“*指針變量名”形式進行計算,容易出錯且閱讀性較差。
?
16,簡單敘述面向?qū)ο蟮娜齻€基本特征
答:封裝性
把客觀事物封裝成抽象的類,對自身的數(shù)據(jù)和方法進行(public,private, protected)
繼承性
繼承概念的實現(xiàn)方式有三類:實現(xiàn)繼承、接口繼承和可視繼承。
實現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力;
接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現(xiàn)的能力;
可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現(xiàn)代碼的能力。
抽象類僅定義將由子類創(chuàng)建的一般屬性和方法,創(chuàng)建抽象類時,請使用關鍵字 Interface 而不是 Class
多態(tài)性
多態(tài)性(polymorphisn)是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,
父對象就可以根據(jù)當前賦值給它的子對象的特性以不同的方式運作。允許將子類類型的指針賦值給父類類型的指針。
實現(xiàn)多態(tài),有二種方式,覆蓋(子類重新定義父類的虛函數(shù)),重載(允許存在多個同名函數(shù),參數(shù)個數(shù),類型不同)。
?
17,類成員函數(shù)的overload, override 和 隱藏的區(qū)別
答:
(1)成員函數(shù)被重載的特征:相同的類范圍,函數(shù)名字相同,參數(shù)不同,virtual 關鍵字可有可無。
(2)覆蓋指派生類的函數(shù)覆蓋基類函數(shù),特征是分別位于基類和派生類,函數(shù)名字相同,參數(shù)相同,基類函數(shù)必須有virtual關鍵字
(3)隱藏是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù)。1,派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同,
不論有無virtual關鍵字,基類的函數(shù)將被隱藏 2,派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,
但是基類函數(shù)沒有virtual 關鍵字。此時,基類的函數(shù)被隱藏
3種情況怎么執(zhí)行:重載:看參數(shù);隱藏:用什么就調(diào)用什么;覆蓋:調(diào)用派生類 。
?
18,什么是預編譯,何時需要預編譯
答:就是指程序執(zhí)行前的一些預處理工作,主要指#表示的.
需要預編譯的情況:總是使用不經(jīng)常改動的大型代碼體。所有模塊都使用一組標準的包含文件和相同的編譯選項。
?
19,memset ,memcpy 和strcpy 的根本區(qū)別?
答:memset用來對一段內(nèi)存空間全部設置為某個字符,一般用在對定義的字符串進行初始化為' '或'';
它對較大的結(jié)構(gòu)體或數(shù)組進行清零操作的一種最快方法。
char temp[30];?????memset(temp,'\0',sizeof(temp));
char temp[30]只是分配了一定的內(nèi)存空間給該字符數(shù)組,但并未初始化該內(nèi)存空間,即數(shù)組。所以,需要使用memset()來進行初始化。
memcpy用來做內(nèi)存拷貝,你可以拿它拷貝任何數(shù)據(jù)類型的對象,可以指定拷貝的數(shù)據(jù)長度;
strcpy就只能拷貝字符串了,它遇到'\0'就結(jié)束拷貝;例:char a[100],b[50];strcpy(a,b);
?
20,多態(tài)類中的虛函數(shù)表是Compile-Time,還是Run-Time時建立的?
答:虛擬函數(shù)表是在編譯期就建立了,各個虛擬函數(shù)這時被組織成了一個虛擬函數(shù)的入口地址的數(shù)組.
而對象的隱藏成員--虛擬函數(shù)表指針是在運行期也就是構(gòu)造函數(shù)被調(diào)用時進行初始化的,這是實現(xiàn)多態(tài)的關鍵.
?
21,Template有什么特點?什么時候用?
答: Template可以獨立于任何特定的類型編寫代碼,是泛型編程的基礎.
當我們編寫的類和函數(shù)能夠多態(tài)的用于跨越編譯時不相關的類型時,用Template.
模板主要用于STL中的容器,算法,迭代器等以及模板元編程.
C++的template是實現(xiàn)在庫設計和嵌入式設計中的關鍵,
能實現(xiàn)抽象和效率的結(jié)合;同時template還能有效地防止代碼膨脹
C++中為什么用模板類?
1)可用來創(chuàng)建動態(tài)增長和減小的數(shù)據(jù)結(jié)構(gòu)
2)它是類型無關的,因此具有很高的可復用性
3)它在編譯時而不是運行時檢查數(shù)據(jù)類型,保證了類型安全
4)它是平臺無關的,可移植性
5)可用于基本數(shù)據(jù)類型
?
22,進程和線程的差別?
答:線程是指進程內(nèi)的一個執(zhí)行單元,也是進程內(nèi)的可調(diào)度實體.區(qū)別:
(1)調(diào)度:線程作為調(diào)度和分配的基本單位,進程作為擁有資源的基本單位
(2)并發(fā)性:不僅進程之間可以并發(fā)執(zhí)行,同一個進程的多個線程之間也可并發(fā)執(zhí)行
(3)擁有資源:進程是擁有資源的一個獨立單位,線程不擁有系統(tǒng)資源,但可以訪問隸屬于進程的資源.
(4)系統(tǒng)開銷:創(chuàng)建撤消進程,系統(tǒng)都要為之分配和回收資源,系統(tǒng)的開銷明顯大于創(chuàng)建撤消線程
多進程與多線程,兩者都可以提高程序的并發(fā)度,提高程序運行效率和響應時間。
?
23,請說出static關鍵字盡可能多的作用
答:(1)函數(shù)體內(nèi)作用范圍為該函數(shù)體,該變量內(nèi)存只被分配一次,具有記憶能力
(2)在模塊內(nèi)的static全局變量可以被模塊內(nèi)所有函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;
(3)在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明它的模塊內(nèi);
(4)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
(5)在類中的static成員函數(shù)屬于整個類所擁有,這個函數(shù)不接收this指針,因而只能訪問類的static成員變量。
?
24,頭文件的作用是什么?
答:一,通過頭文件來調(diào)用庫功能。在很多場合,源代碼不便(或不準)向用戶公布,只要向用戶提供頭文件
和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調(diào)用庫功能,而不必關心接口怎么實現(xiàn)的。
編譯器會從庫中提取相應的代碼。
二,頭文件能加強類型安全檢查。如果某個接口被實現(xiàn)或被使用時,其方式與頭文件中的聲明不一致,
編譯器就會指出錯誤,這一簡單的規(guī)則能大大減輕程序員調(diào)試、改錯的負擔。
?
25,在C++程序中調(diào)用C編譯后的函數(shù),為什么要加extern C的聲明?
答:因為C++支持函數(shù)重載,而C不支持函數(shù)重載,函數(shù)被C++編譯后在庫中的名字與C語言的不同。
假設某個函數(shù)的原型為:void foo(int x, int y);該函數(shù)被C編譯器編譯后在庫中的名字為_foo,
而C++編譯器則產(chǎn)生像_foo_int_int之類的名字。 C++提供extern C來解決名字匹配問題
?
26,C++中哪些函數(shù)不能被聲明為虛函數(shù)?
答:普通函數(shù)(非成員函數(shù)),構(gòu)造函數(shù),內(nèi)聯(lián)成員函數(shù)、靜態(tài)成員函數(shù)、友元函數(shù)。
(1)虛函數(shù)用于基類和派生類,普通函數(shù)所以不能
(2)構(gòu)造函數(shù)不能是因為虛函數(shù)采用的是虛調(diào)用的方法,允許在只知道部分信息的情況的工作機制,
特別允許調(diào)用只知道接口而不知道對象的準確類型的方法,但是調(diào)用構(gòu)造函數(shù)即使要創(chuàng)建一個對象,
那勢必要知道對象的準確類型。
(3)內(nèi)聯(lián)成員函數(shù)的實質(zhì)是在調(diào)用的地方直接將代碼擴展開
(4)繼承時,靜態(tài)成員函數(shù)是不能被繼承的,它只屬于一個類,因為也不存在動態(tài)聯(lián)編等
(5)友元函數(shù)不是類的成員函數(shù),因此也不能被繼承
?
27, 數(shù)組int c[3][3]; 為什么c,*c的值相等,(c+1),(*c+1)的值不等, c,*c,**c,代表什么意思?
答:c是第一個元素的地址,*c是第一行元素的首地址,其實第一行元素的地址就是第一個元素的地址,
**c是提領第一個元素。 為什么c,*c的值相等?
c: 數(shù)組名;是一個二維指針,它的值就是數(shù)組的首地址,也即第一行元素的首地址(等于 *c),
也等于第一行第一個元素的地址( & c[0][0]);可以說成是二維數(shù)組的行指針。
*c: 第一行元素的首地址;是一個一維指針,可以說成是二維數(shù)組的列指針。
**c:二維數(shù)組中的第一個元素的值;即:c[0][0]
所以:c 和 *c的值是相等的,但他們兩者不能相互賦值,(類型不同)
(c + 1) :c是行指針,(c + 1)是在c的基礎上加上二維數(shù)組一行的地址長度,
即從&c[0][0]變到了&c[1][0];
(*c + 1):*c是列指針,(*c + 1)是在*c的基礎上加上二數(shù)組一個元素的所占的長度,
&c[0][0]變到了&c[0][1],從而(c + 1)和(*c + 1)的值就不相等了。
?
28,定義??int **pa[4][3],則變量pa占有的內(nèi)存空間是多少?
答:int **p,在32位機器上 sizeof(p) = 4;
總共占有4*3*sizeof(p) = 48.
?
29,拷貝構(gòu)造函數(shù)相關問題,深拷貝,淺拷貝,臨時對象等
答:在C++中,三種對象需要拷貝的情況:一個對象以值傳遞的方式傳入函數(shù)體,
?一個對象以值傳遞的方式從函數(shù)返回,一個對象需要通過另外一個對象進行初始化。
執(zhí)行先父類后子類的構(gòu)造,對類中每一個數(shù)據(jù)成員遞歸地執(zhí)行成員拷的動作.
深拷貝:如果一個類擁有資源,深拷貝意味著拷貝了資源和指針
淺拷貝:如果對象存在資源,而淺拷貝只是拷貝了指針,沒有拷貝資源,
這樣使得兩個指針指向同一份資源,造成對同一份析構(gòu)兩次,程序崩潰。
臨時對象的開銷比局部對象小些。
?
臨時對象:輔助一個表達式的計算 a + b + c ,或者間接構(gòu)造的實參,函數(shù)返回非引用的時候,
都可能產(chǎn)生臨時對象,臨時對象生命周期,是單個語句,是右值。
臨時對象的開銷比局部對象小些。
?
30,指針和引用有什么分別;
答:引用必須初始化,即引用到一個有效的對象;而指針在定義的時候不必初始化,
可以在定義后面的任何地方重新賦值。
引用初始化后不能改變,指針可以改變所指的對象
不存在指向NULL的引用,但存在指向NULL的指針
引用的創(chuàng)建和銷毀并不會調(diào)用類的拷貝構(gòu)造函數(shù)
語言層面,引用的用法和對象一樣;在二進制層面,引用一般都是通過指針來實現(xiàn)的,
只不過編譯器幫我們完成了轉(zhuǎn)換.引用既具有指針的效率,又具有變量使用的方便性和直觀性.
?
31,寫一個"標準"宏MIN,這個宏輸入兩個參數(shù)并返回較小的一個
答:面試者注意謹慎將宏定義中的“參數(shù)”和整個宏用括號括起來
#define??????MIN(A, B)?????((A) <= (B)? (A):(B))
?
32,用一個宏定義FIND求一個結(jié)構(gòu)體struc中某個變量相對struc的偏移量
答:??#define FIND(struc, e)??(size_t)&( ((struc*)0)->e )
解析:其中(struc*)0表示將常量0轉(zhuǎn)化為struc*類型指針所指向的地址。
&( ((struc*)0)->e )表示取結(jié)構(gòu)體指針(struc*)0的成員e的地址,因為該結(jié)構(gòu)體的首地址為0,
所以其實就是得到了成員e距離結(jié)構(gòu)體首地址的偏移量,(size_t)是一種數(shù)據(jù)類型,為了便于不同系統(tǒng)之間的移植,
最好定義為一種無符號型數(shù)據(jù),一般為unsigned int
?
33,解析sizeof 以及 結(jié)構(gòu)體的對齊問題
答:(1)sizeof(type),用于數(shù)據(jù)類型;
sizeof(var_name)或sizeof var_name用于變量
sizeof操作符不能用于函數(shù)類型,不完全類型或位字段。
不完全類型指具有未知存儲大小的數(shù)據(jù)類型,如未知存儲大小的數(shù)組類型、未知內(nèi)容的結(jié)構(gòu)或聯(lián)合類型、void類型等。
如int max(),??char char_v [MAX]且MAX未知??, void類型
那么sizeof(max),sizeof(char_v),sizeof(void)都是錯誤的
?
當sizeof的參數(shù)為數(shù)組或者指針時
int???a[50];?????//sizeof(a)=4*50=200;???求數(shù)組所占的空間大小
int???*a=new???int[50];//???sizeof(a)=4;???a為一個指針,sizeof(a)是求指針??
當sizeof的參數(shù)為結(jié)構(gòu)或類時候
結(jié)構(gòu)或者類中的靜態(tài)成員不對結(jié)構(gòu)或者類的大小產(chǎn)生影響,因為靜態(tài)變量的存儲位置 。
與結(jié)構(gòu)或者類的實例地址無關。沒有成員變量的結(jié)構(gòu)或類的大小為1,
因為必須保證結(jié)構(gòu)或類的每一 實例在內(nèi)存中都有唯一的地址
?
(2)class MyStruct{???double ddal;????char dda;????int type;}
在VC中測試上面結(jié)構(gòu)的大小時,你會發(fā)現(xiàn)sizeof(MyStruct)為16。
其實,這是VC對變量存儲的一個特殊處理。為了提高CPU的存儲速度,VC對一些變量的起始
地址做了“對齊”處理。在默認情況下,VC規(guī)定各成員變量存放的起始地址相對于結(jié)構(gòu)的
始地址偏移量必須為該變量的類型占用字節(jié)數(shù)的倍數(shù),如Char偏移量為sizeof(char)即1的倍數(shù)
?
先為第一個成員dda1分配空間,其起始地址跟結(jié)構(gòu)的起始地址相同,偏移量0剛好為sizeof(double)的倍數(shù),
該成員變量占用sizeof(double)=8個字節(jié);接下來為第二個成員dda分配空間,這時
下一個可以分配的地址對于結(jié)構(gòu)的起始地址的偏移量為8,是sizeof(char)的倍數(shù),占sizeof(char)=1字節(jié)
為第三個成員type分配空間,這時下一個可以分配的地址對于結(jié)構(gòu)的起始地址的偏移量為9
,不是sizeof(int)=4的倍數(shù),為了滿足對齊方式對偏移量的約束問題,VC自動填充3個字節(jié)
這時下一個可以分配的地址對于結(jié)構(gòu)的起始地址的偏移量是12,剛好是sizeof(int)=4的倍數(shù),
所以把type存放在偏移量為12的地方,占 用sizeof(int)=4個字節(jié)??偟恼加玫目臻g大
小為:8+1+3+4=16,剛好為結(jié)構(gòu)的字節(jié)邊界數(shù)(即結(jié)構(gòu)中占用最大空間的類型所占用的字節(jié)
數(shù)sizeof(double)=8)的倍數(shù),所以沒有空缺的字節(jié)需要填充。
?
34,在main函數(shù)執(zhí)行之前,還會執(zhí)行什么代碼和工作
答:運行全局構(gòu)造器,全局對象的構(gòu)造函數(shù)會在main函數(shù)之前執(zhí)行
設置棧指針,初始化static靜態(tài)和global全局變量,即數(shù)據(jù)段的內(nèi)容
將未初始化部分的賦初值:數(shù)值型short,int,long等為0,bool為FALSE,指針為NULL等
將main函數(shù)的參數(shù),argc,argv等傳遞給main函數(shù)
?
35,如何判斷一段程序是由C 編譯程序還是由C++ 編譯程序編譯的?
答:C++ 編譯時定義了 __cplusplus
C 編譯時定義了 _STDC_
?
36,分別寫出BOOL,int, float, 指針類型的變量 a 與 “零值”的比較語句
答:
??BOOL: if(!a)???or???if(a)
????int : if( 0 == a)
??float : const EXPRESSION EXP = 0.000001;
??if(a < EXP && a > -EXP)
?pointer:?????if(a != NULL) or??if(a == NULL)
?
37,已知String類定義如下,嘗試寫出類的成員函數(shù)實現(xiàn)
class{
public:
String(const char*str = NULL);?????????????//通用構(gòu)造函數(shù)
String(const String& another);?????????????//拷貝構(gòu)造函數(shù)
~String();?????????????????????????????????//析構(gòu)函數(shù)
String& operator = = (const String& rhs);??//賦值函數(shù)
private:
char* m_data;??????????????????????????????//用于保存字符串
};
?
答:
String::String(const char*str)
{
?????if(str == NULL)
?????{
????????????m_data = new char[1];
????????????m_data[0] = '\0';
?????}
?????else
?????{
????????????m_data = new char[strlen(str)+1];
????????????strcpy(m_data, str);????????
?????}
}???
String::String(const String& another)
{
?????m_data = new char[strlen(another.m_data)+1];
?????strcpy(m_data, another.m_data);?
}??????????????????????????
String::String& operator = = (const String& rhs)
{
????if(this == &rhs)
????return &this;
????delete[]??m_data;
????m_data = new char(strlen(rhs.m_data)+1);???//刪除原來的數(shù)據(jù),新開一塊內(nèi)存
???strcpy(m_data, rhs.m_data);?
?????return *this;
}
~String()
{
????delete[]??m_data;
}
?
38,論述C++類繼承的優(yōu)缺點
答:一,優(yōu)點:類繼承是在編譯時刻靜態(tài)定義的,可以直接使用,類繼承可以較方便的改變從父類繼承的實現(xiàn)
二,缺點:1,因為繼承在編譯時刻就定義了,所以無法在運行時刻改變從父類繼承的實現(xiàn)
2,父類通常至少定義了子類的部分行為,父類的任何改變都可能影響到子類的行為
3,如果繼承下來的實現(xiàn)不適合解決新的問題,則父類必須重寫或被其他更適合的類替換
這種依賴關系先限制了靈活性并最終限制了復用性
?
39,運算符重載的三種方式和不允許重載的5個運算符
答:運算符重載意義是為了對用戶自定義數(shù)據(jù)的操作和內(nèi)定義的數(shù)據(jù)類型的操作形式一致
(1)普通函數(shù),友元函數(shù),類成員函數(shù)
(2).*(成員指針訪問運算符)???
??????::(域運算符)?
??????sizeof 長度運算符???
?????:條件運算符???
?????.(成員訪問運算符)
40,友元關系有什么特性?
答:單向的,非傳遞的, 不能繼承的.
?
41,理解析構(gòu)函數(shù)和虛函數(shù)的用法和作用?
答:析構(gòu)函數(shù)也是特殊的類成員函數(shù),它沒有返回類型,沒有參數(shù),不能隨意調(diào)用,也沒有重載。
在類對象生命期結(jié)束的時候,由系統(tǒng)自動調(diào)用釋放在構(gòu)造函數(shù)中分配的資源。
析構(gòu)函數(shù)一般在對象撤消前做收尾工作,比如回收內(nèi)存等工作。
?
虛函數(shù)的功能是使子類可以用同名的函數(shù)對父類函數(shù)進行重載,并且在調(diào)用時自動調(diào)用子類重載函
數(shù),在基類中通過使用關鍵字virtual來聲明一個函數(shù)為虛函數(shù),該函數(shù)的功能可能在將來的派生類
中定義或者在基類的基礎上擴展,系統(tǒng)只能在運行階段才能動態(tài)的決定調(diào)用哪一個函數(shù),動態(tài)的多態(tài)性,
如果是純虛函數(shù),則純粹是為了在子類重載時有個統(tǒng)一的命名而已。
?
42,關鍵字volatile有什么含意?并給出三個不同的例子
答:一個定義為volatile的變量是說這變量可能會被意想不到地改變,編譯器就不會去假設這個變量的值了。
精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值
而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
1) 并行設備的硬件寄存器(如:狀態(tài)寄存器)
2) 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
3) 多線程應用中被幾個任務共享的變量
?
深究:一個參數(shù)既可以是const還可以是volatile,一個例子是只讀的狀態(tài)寄存器,
它是volatile因為它可能被意想不到地改變,是const因為程序不應該試圖去修改它。
一個指針可以是volatile,一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
?
43,動態(tài)連接庫的兩種方式?
答:調(diào)用一個DLL中的函數(shù)有兩種方法:
1.載入時動態(tài)鏈接(load-time dynamic linking),模塊非常明確調(diào)用某個導出函數(shù)
,使得他們就像本地函數(shù)一樣。這需要鏈接時鏈接那些函數(shù)所在DLL的導入庫,導入庫向
系統(tǒng)提供了載入DLL時所需的信息及DLL函數(shù)定位。
2.運行時動態(tài)鏈接(run-time dynamic linking),運行時可以通過LoadLibrary或Loa
dLibraryEx函數(shù)載入DLL。DLL載入后,模塊可以通過調(diào)用GetProcAddress獲取DLL函數(shù)的
出口地址,然后就可以通過返回的函數(shù)指針調(diào)用DLL函數(shù)了。如此即可避免導入庫文件了。
?
44,C和C++有什么不同?
答:從機制上:c是面向過程的。c++是面向?qū)ο蟮?#xff0c;提供了類。c++編寫面向?qū)ο蟮某绦虮萩容易。
從適用的方向:c適合要求代碼體積小的,效率高的場合,如嵌入式;c++適合更上層的,復雜的;?
llinux核心大部分是c寫的,因為它是系統(tǒng)軟件,效率要求極高。
C語言是結(jié)構(gòu)化編程語言,C++是面向?qū)ο缶幊陶Z言
C++側(cè)重于對象而不是過程,側(cè)重于類的設計而不是邏輯的設計。
?
45,C++編譯器自動為類產(chǎn)生的四個確缺省函數(shù)是什么?
答:默認構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),析構(gòu)函數(shù),賦值函數(shù)
?
46,簡單描述Windows內(nèi)存管理的方法。
答:程序運行時需要從內(nèi)存中讀出這段程序的代碼,代碼的位置必須在物理內(nèi)存中才能被運行,
由于現(xiàn)在的操作系統(tǒng)中有非常多的程序運行著,內(nèi)存中不能夠完全放下,所以引出了虛擬內(nèi)存的概念。
把哪些不常用的程序片斷就放入虛擬內(nèi)存,當需要用到它的時候在load入主存(物理內(nèi)存)中。
內(nèi)存管理也計算程序片段在主存中的物理位置,以便CPU調(diào)度。
?
內(nèi)存管理有塊式管理,頁式管理,段式和段頁式管理。現(xiàn)在常用段頁式管理
塊式管理:把主存分為一大塊、一大塊的,當所需的程序片斷不在主存時就分配一塊主存空間,
把程 序片斷l(xiāng)oad入主存,就算所需的程序片度只有幾個字節(jié)也只能把這一塊分配給它。
這樣會造成很大的浪費,平均浪費了50%的內(nèi)存空間,但時易于管理。
頁式管理:把主存分為一頁一頁的,每一頁的空間要比一塊一塊的空間小很多,顯然這種方法
的空間利用率要比塊式管理高很多
段式管理:把主存分為一段一段的,每一段的空間又要比一頁一頁的空間小很多,
這種方法在空間利用率上又比頁式管理高很多,但是也有另外一個缺點。一個程序片斷可能會被分為幾十段,
這樣很多時間就會被浪費在計算每一段的物理地址上,計算機最耗時間的大家都知道是I/O吧
段頁式管理:結(jié)合了段式管理和頁式管理的優(yōu)點。把主存分為若干頁,每一頁又分為若干段,好處就很明顯
?
47,Linux有內(nèi)核級線程嗎?
答:線程通常被定義為一個進程中代碼的不同執(zhí)行路線。從實現(xiàn)方式上劃分,線程有兩種類型:
“用戶級線程”和“內(nèi)核級線程”。 用戶線程指不需要內(nèi)核支持而在用戶程序中實現(xiàn)的線程,其不依賴于操作系統(tǒng)核心,
應用進程利用線程庫提供創(chuàng)建、同步、調(diào)度,和管理線程的函數(shù)來控制用戶線程。內(nèi)核級線程需要內(nèi)核的參與,
由內(nèi)核完成線程的調(diào)度。其依賴于操作系統(tǒng)核心,由內(nèi)核的內(nèi)部需求進行創(chuàng)建和撤銷。
?
用戶線程不需要額外的內(nèi)核開支,并且用戶態(tài)線程的實現(xiàn)方式可以被定制或修改以適應特殊應用的要求,
但是當一個線程因 I/O 而處于等待狀態(tài)時,整個進程就會被調(diào)度程序切換為等待狀態(tài),其他線程得不
到運行的機會;而內(nèi)核線程則沒有這個個限制,有利于發(fā)揮多處理器的并發(fā)優(yōu)勢,但卻占用了更多的系統(tǒng)開支。
?
48,main 主函數(shù)執(zhí)行完畢后,是否可能會再執(zhí)行一段代碼,給出說明?
答:可以,可以用_onexit 注冊一個函數(shù),它會在main 之后執(zhí)行int fn1(void), fn2(void), fn3(void), fn4 (void)
?
49, i++ 相比 ++i 哪個更高效?為什么?
答:
(1)++i 比 i++效率高。
(2)i++要多調(diào)用一次類的構(gòu)造和析夠函數(shù)
?
50,windows平臺下網(wǎng)絡編程有哪幾種網(wǎng)絡編程模型?
答:有阻塞,select,基于窗體的事件模型,事件模型,重疊模型,完成端口模型。
除了阻塞模型外,其他都是非阻塞模型,其中效率最高的是完成端口模型,尤其在windows下服務器最合適了。
做客戶端一般用事件模型了,select在window和類unix都可以使用。
?
51,什么是函數(shù)模板
答:函數(shù)模板技術定義了參數(shù)化的非成員函數(shù),使得程序能夠使用不同的參數(shù)類型調(diào)用相同的函數(shù),而至于是何種類型,
則是由編譯器確定從模板中生成相應類型的代碼。編譯器確定了模板函數(shù)的實際類型參數(shù),稱之為模板的實例化。
template<class T>定義模板標識
T Add(T a, T b)?????????//函數(shù)模板
{
???T result = a + b;
???return a + b;????//將兩個參數(shù)使用“+”運算符進行運算,這兩個參數(shù)并不知道是何種類型
}
該函數(shù)與一般函數(shù)的不同之處在于沒有明確指出使用何種數(shù)據(jù)類型和返回值又是哪一種類型
如何在程序中調(diào)用該函數(shù)
#include<iostream>??//包含標準輸入輸出頭文件
#include<string>???//C++中的字符串處理頭文件
using namespace std;
template<class T>
T Add(T a, T b)?????????//函數(shù)模板
{
???T result = a + b;
???return a + b;????//將兩個參數(shù)使用“+”運算符進行運算,這兩個參數(shù)并不知道是何種類型
}
int main(int argc, char* argv[])
{
????cout<<"2+3="<<Add(2,3)<<endl;??//輸出整形的+運算結(jié)果
???cout<<"sdf+123="<<Add(string("sdf"), string("123"))<<endl;
??return 0;
}
?
52,什么是類模板
答:描述了能夠管理其他數(shù)據(jù)類型的通用數(shù)據(jù)類型,通常用于建立包含其他類型的容器類
對于這些容器,無論是哪一種數(shù)據(jù)類型,其操作方式是一樣的,但是針對具體的類型又是專用的,
template<class T>
class TemplateSample
{
???private:
????T& emtity;????????????//使用參數(shù)類型成員
????public:
??void F(T& arg);????????//使用參數(shù)類型定義成員函數(shù)
}
該示例定義了一個類模板,類模板中的模板形參T需要用戶在使用的時候進行定義
TemplateSample<int>demo;???//針對該模板使用int類型
demo.F(123);???//調(diào)用類模板中的成員函數(shù)
template<class T1, class T2, int num>??????//定義多個模板參數(shù),且其中一個直接使用int類型
該示例的前兩個參數(shù)可以是任何類型,但是第三個參數(shù)一定是int類型
TemplateSample<int , char, 12>demo;??????//使用非類類型的模板
#include<iostream>
template<class T, class T2, int num>
class CSampleTemplate
{
???private:
???T t1;
???T2 t2;
??public:
??CSampleTemplate(T arg1, T2 arg2)?????????//構(gòu)造函數(shù)中使用模板參數(shù)
??{
??????t1 = arg1 + num;
??????t2 = arg2 + num;
??}
??void Write()
?{
??std::cout<<"t1:"<<t1<<"t2"<<t2<<endl;
?}
?
CSampleTemplate ()
{}
}
int main(int argc, char* argv[])
{
????CSampleTemplate<int, int, 3>temp(1,2);
????temp.Write();
????return 0;
}
53,什么是容器
答:STL是一個標準的C++庫,容器只是其中一個重要的組成部分,有順序容器和關聯(lián)容器
1)順序容器,指的是一組具有相同類型T的對象,以嚴格的線性形式組織在一起
包括vector<T>,???deque<T>,????list<T>
2)關聯(lián)容器,提供一個key實現(xiàn)對對象的隨機訪問,其特點是key是有序的元素是按照預定義的鍵順序插入的i
set<Key> ,集合,???支持唯一鍵值,提供對鍵本身的快速檢索,例如set<long>:{學號}
set<Key>,多重集合,支持可重復鍵值,提供對鍵本身的快速檢索,例如multiset<string>:{姓名}
map<Key, T>,支持唯一Key類型的鍵值,提供對另一個基于鍵的類型的快速檢索,例如map<long,string>:{學號,姓名}
multimap<Key, T>, 多重映射,支持可重復Key值,提供對另外一個基于鍵類型T的快速檢索,例如map<string, string>:{姓名,地址}
?
54,介紹關聯(lián)容器
答:#include<vector>?????//包含頭文件
using std::vector???????????//使用命名限定
vector<int>vInts;
創(chuàng)建一個Widget類型為空的vector對象
vector<Widget>vWidgets;????????????????????//空的vector對象
vector<Widget>vWidgets(500);?????????????//包含500個對象的vector
vector<Widget>vWidgets(500, Widget(0));???????//包含500個對象的vector,并且初始化為0
vector<Widget>vWidgetFromAnother(vWeigets);????????//利用現(xiàn)有的vector創(chuàng)建一個拷貝
向vector中添加一個數(shù)據(jù),默認方式是push_back,表示將數(shù)據(jù)添加到vector的尾部,并且按照需要來分配內(nèi)存,如
for(int i = 0 ; i < 10; i ++)
v.push_back(Widget(i));
?
如果想獲取vector v的大小,但不知道它是否為空,或者已經(jīng)包含了數(shù)據(jù),可用如下代碼實現(xiàn)
int nSize = v.empty()? -1:static_cast<int>(v.size());
?
訪問vector中的數(shù)據(jù)有兩種方法 vector::at()???和??vector::operator[],其中vector::at()進行了邊界檢查
?
vector<int>v;??????????????????//定義了vector對象
v.reserve(10);?????????????????????//分配空間但是沒有初始化
for(int i = 0 ; i < 7; i++)
{??v. push_back(i);}
int iVal1 = v[7];????????????????????//不進行邊界檢查
int iVal2 = v.at(7);???????????//進行邊界檢查
?
deque容器是一個雙端隊列,存放的元素不是以連續(xù)的方式存放的
list容器是一種鏈表的實現(xiàn),儲存的元素是通過使用雙向鏈表實現(xiàn)的
?
55,什么是迭代器的范圍
答:迭代器是STL提供的對一個容器中的對象的訪問方法,定義了容器中對象的范圍,迭代器就如同一個指針。
vector<int>v;?????//聲明vector變量
v.push_back(2);????//插入數(shù)據(jù)
v.push_back(1);
vector<int>::iterator first = v.begin();??????//獲取vector<int>的一個元素的迭代器
while1(first != v.end())???????????//使用迭代器遍歷vector,一直到最后一個元素
{
???int i = *first;?????//獲取迭代器指向的元素的值
first++;
}
?
55,C++如何實現(xiàn)泛型編程
答:泛型編程實現(xiàn)了于特定類型的操作算法,由編譯器根據(jù)泛型的調(diào)用所傳遞的類及模板生成該類型專用的代碼。
#include<iostream>
#include<string>
using namespaces std;
template<class T>
T Add(T a, T b)
{
????T result;???????????// 使用參數(shù)化的類型定義變量
???result = a + b;
??return result;
}
int main(int argc, char* argv[])
{
??cout<<"2+3="<<Add(2,3)<<endl;??
??cout<<"sdf+123="<<Add(string("sdf"), string("123"));
???return 0;
}
?
56,參數(shù)傳遞的方式和多態(tài)參數(shù)傳遞的實現(xiàn)
答:參數(shù)傳遞有傳值,傳指針,或者是引用等三種,下面做詳細的介紹
1)傳值方式適合一般的數(shù)值傳遞,并且不改變原數(shù)據(jù),但是要消耗內(nèi)存空間
2)傳遞指針方式適合傳遞數(shù)組和指針,由于傳遞的是地址,所以直接操作會改變原數(shù)據(jù)
3)引用方式和指針方式比較類似,是相對比較新的一種方式,一般情況下能用傳地址的就能用引用
而且使用引用更方便一些
實現(xiàn)多態(tài)主要是采用指針和引用,傳值方式是復制數(shù)據(jù),其類型編譯器就已經(jīng)決定,而多態(tài)是類型要等到執(zhí)行器才能決定,
所以不適用傳值方式來實現(xiàn)多態(tài)參數(shù)傳遞
?
57,C++和C定義結(jié)構(gòu)體區(qū)別是什么?
答:C++中的結(jié)構(gòu)和類其實具備幾乎一樣的功能,結(jié)構(gòu)體內(nèi)也是可以聲明函數(shù),C++的結(jié)構(gòu)體和類默認具有不一樣的訪問屬性
?
轉(zhuǎn)載于:https://www.cnblogs.com/D-DZDD/p/7197210.html
總結(jié)
- 上一篇: python3 logging模块
- 下一篇: 构造方法: