版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
8:以下多重繼承時的二義性問題如何解決?classA{//類A的定義public:voidprint(){cout<<"Hello,thisisA"<<endl;}};classB{//類B的定義public:voidprint(){cout<<"Hello,thisisB"<<endl;}};classC:publicA,publicB{ //類C由類A和類B共同派生而來public:voiddisp(){print();}//編譯器無法決定采用A類中定義的版本還是B類中的版本};解答:假設(shè)兩個基類中具有同名的數(shù)據(jù)成員或成員函數(shù),應(yīng)使用成員名限定來消除二義性,如:voiddisp(){A::print(); //加成員名限定A::}但更好的方法是在類C中也定義一個同名print函數(shù),根據(jù)需要調(diào)用A::print()還是B::print(),從而實(shí)現(xiàn)對基類同名函數(shù)的隱藏9:以下公共基類導(dǎo)致的二義性如何解決?classA{ //公共基類public: //public成員列表voidprint(){cout<<"thisisxinA:"<<endl;}classB:publicA{};classC:publicA{};classD:publicB,publicC{};voidmain(){Dd; //聲明一個D類對象dA*pa=(A*)&d; //上行轉(zhuǎn)換產(chǎn)生二義性d.print(); //print()具有二義性,系統(tǒng)不知道是調(diào)用B類的還是C類的print()函數(shù)}注意:把子類的指針或引用轉(zhuǎn)換成基類指針或引用是上行轉(zhuǎn)換,把基類指針或引用轉(zhuǎn)換成子類指針或引用是下行轉(zhuǎn)換。解答:1)main函數(shù)中語句“d.print();〞編譯錯誤,可改為以下的一種:d.B::print();d.C::print();假設(shè)改為“d.A::print();〞又會如何呢?由于d對象中有兩個A類對象,故編譯會報“基類A不明確〞。語句“A*pa=(A*)&d;〞產(chǎn)生的二義性是由于d中含有兩個基類對象A,隱式轉(zhuǎn)換時不知道讓pa指向哪個子對象,從而出錯??筛臑橐韵碌囊环N:A*pa=(A*)(B*)&d;//上行轉(zhuǎn)換A*pa=(A*)(C*)&d;//上行轉(zhuǎn)換事實(shí)上,使用關(guān)鍵字virtual將共同基類A聲明為虛基類,可有效解決上述問題。10:下面哪種情況下,B不能隱式轉(zhuǎn)換為A( )?(2023?騰訊〕A.classB:publicA{} B.classA:publicB{}C.classB{operatorA();} D.classA{A(constB&);}解答:B。因?yàn)樽宇惏烁割惥植?,所以子類可以轉(zhuǎn)換為父類,但是相反,父類沒有子類額外定義的局部,所以不能轉(zhuǎn)換為子類,故A正確,而B錯誤。非C++內(nèi)建型別A和B,在以下幾種情況下B能隱式轉(zhuǎn)化為A。B公有繼承自A,可以是間接繼承的。classB:publicA{};此時假設(shè)有“Aa;Bb;〞,那么“a=b;〞合法。B中有類型轉(zhuǎn)換函數(shù)。classB{operatorA();};此時假設(shè)有“Aa;Bb;〞,那么“a=b;〞合法。A實(shí)現(xiàn)了非explicit的參數(shù)為B(可以有其他帶默認(rèn)值的參數(shù)〕的構(gòu)造函數(shù)classA{A(constB&);};此時假設(shè)有“Aa;Bb;〞,那么“a=b;〞合法。11:調(diào)用一成員函數(shù)時,使用動態(tài)聯(lián)編的情況是〔〕?!?023?淘寶〕A.通過對象調(diào)用一虛函數(shù)B.通過指針或引用調(diào)用一虛函數(shù)C.通過對象調(diào)用靜態(tài)函數(shù)D.通過指針或引用調(diào)用一靜態(tài)函數(shù)解答:B。結(jié)合一段例如代碼來看虛函數(shù)的作用,以幫助大家理解多態(tài)的意義所在。例2:下述代碼的輸出結(jié)果是什么?classbase{public:virtualvoiddisp(){cout<<"hello,base1"<<endl;}voiddisp2(){cout<<"hello,base2"<<endl;}};classchild1:publicbase{public:voiddisp(){cout<<"hello,child1"<<endl;}voiddisp2(){cout<<"hello,child2"<<endl;}voidmain(){base*base=NULL;child1objchild1;base=&objchildl;base->disp();base->disp2();解答:輸出:hello,childlhello,base2從上述代碼可見,通過指針訪問函數(shù)時:不加virtual時,具體調(diào)用哪個版本的函數(shù)只取決于指針本身的類型,和指針?biāo)笇ο蟮念愋蜔o關(guān)。而加virtual時,具體調(diào)用哪個版本的函數(shù)不再取決于指針本身的類型,而是取決于指針?biāo)笇ο蟮念愋汀?3:構(gòu)造函數(shù)為什么不能為虛函數(shù)?解答:假設(shè)有如下代碼:classA{A(){}};classB:publicA{B():A() {}};intmain(){Bb;B*pb=&b;}那么構(gòu)造B類的對象時:根據(jù)繼承的性質(zhì),構(gòu)造函數(shù)執(zhí)行順序是:A()B()根據(jù)虛函數(shù)的性質(zhì),如果A的構(gòu)造函數(shù)為虛函數(shù),且B類也給出了構(gòu)造函數(shù),那么應(yīng)該只執(zhí)行B類的構(gòu)造函數(shù),不再執(zhí)行A類的構(gòu)造函數(shù)。這樣A就不能構(gòu)造了。這樣1和2就發(fā)生了矛盾。另外,virtual函數(shù)是在不同類型的對象產(chǎn)生不同的動作,現(xiàn)在對象還沒有產(chǎn)生,如何使用virtual函數(shù)來完成你想完成的動作。14:哪些函數(shù)不能為虛函數(shù)?解答:常見的不能聲明為虛函數(shù)的有:普通函數(shù)〔非成員函數(shù))、靜態(tài)成員函數(shù)、構(gòu)造函數(shù)、友元函數(shù),而內(nèi)聯(lián)成員函數(shù)、賦值操作符重載函數(shù)即使聲明為虛函數(shù)也無意義。為什么C++不支持普通函數(shù)為虛函數(shù)?普通函數(shù)〔非成員函數(shù)〕只能被overload(重載),不能被override(覆蓋),聲明為虛函數(shù)也沒有什么意義,因此編譯器會在編譯時綁定函數(shù)。為什么C++不支持構(gòu)造函數(shù)為虛函數(shù)?上例己經(jīng)給出了答案。為什么C++不支持靜態(tài)成員函數(shù)為虛函數(shù)?靜態(tài)成員函數(shù)對于每個類來說只有一份代碼,所有的對象都共享這一份代碼,它不歸某個具體對象所有,所以它沒有要動態(tài)綁定的必要性。為什么C++不支持友元函數(shù)為虛函數(shù)?因?yàn)镃++不支持友元函數(shù)的繼承,沒有實(shí)現(xiàn)為虛函數(shù)的必要。以下兩種函數(shù)被聲明為虛函數(shù)時,雖然編譯器不會報錯,但是毫無意義。內(nèi)聯(lián)函數(shù):內(nèi)聯(lián)函數(shù)是為了在代碼中直接展開,減少函數(shù)調(diào)用花費(fèi)的代價,虛函數(shù)是為了在繼承后,對象能夠準(zhǔn)確地執(zhí)行自己的動作,這是不可能統(tǒng)一的。即使虛函數(shù)被聲明為內(nèi)聯(lián)函數(shù),編譯器遇到這種情況根本不會把這樣的函數(shù)內(nèi)聯(lián)展開,而是當(dāng)作普通函數(shù)來處理。賦值運(yùn)算符:雖然可以在基類中將成員函數(shù)operator定義為虛函數(shù),但這樣做沒有意義。賦值操作符重載函數(shù)要求形參與類本身類型相同,故基類中的賦值操作符形參類型為基類類型,即使聲明為虛函數(shù),也不能作為子類的賦值操作符。15:以下描述正確的選項(xiàng)是〔〕?!?023?盛大游戲〕虛函數(shù)是可以內(nèi)聯(lián)的,可以減少函數(shù)調(diào)用的開銷提高效率類里面可以同時存在函數(shù)名和參數(shù)都一樣的虛函數(shù)和靜態(tài)函數(shù)父類的析構(gòu)函數(shù)是非虛的,但是子類的析構(gòu)函數(shù)是虛的,delete子類對象指針會調(diào)用父類的析構(gòu)函數(shù)D?以上都不對解答:C。C中delete子類對象指針會調(diào)用父類的析構(gòu)函數(shù)〔即使子類的析構(gòu)函數(shù)不是虛的,對子類對象指針調(diào)用析構(gòu)函數(shù),也會調(diào)用父類的析構(gòu)函數(shù)),但假設(shè)delete父類對象指針卻不會調(diào)用子類的析構(gòu)函數(shù)〔因?yàn)楦割惖奈鰳?gòu)函數(shù)不是虛函數(shù),不執(zhí)行動態(tài)綁定)。16:以下代碼的輸出結(jié)果是〔〕。〔2023?小米〕classB{public:B(){cout<<〞Bconstructor,〞;s=“B〞;}voidf(){cout<<s;}peivate:strings;};classD:publicB{public:D():B(){cout<<"Dconstructor,";s=“D〞;}voidf(){cout<<s;}private:strings;};intmain(void){B*b=newD();b->f();((D*)b)->f();deleteb;return0;}解答:輸出結(jié)果是:Bconstructor,Dconstructor,BD假設(shè)在類B中的函數(shù)f前加上virtual關(guān)鍵字,那么輸出結(jié)果為:Bconstructor,Dconstructor,DD可見假設(shè)函數(shù)不是虛函數(shù),那么不是動態(tài)綁定。17:以下代碼的輸出結(jié)果是什么?〔2023?網(wǎng)易〕classA{public:virtualvoidFun(intnumber=10){std::cout<<"A::Funwithnumber"<<number<<endl;}};classB:publicA{public:virtualvoidFun(intnumber=20){std::cout<<〞B::Funwithnumber’’<<number<<endl;}};intmain(){Bb;A&a=b;a.Fun();return0;}解答:B::Funwithnumber10。虛函數(shù)動態(tài)綁定到B,但缺省實(shí)參是編譯時候確定的10,而非20。構(gòu)造函數(shù)和析構(gòu)函數(shù)中的虛函數(shù)構(gòu)造派生類對象時,首先運(yùn)行基類構(gòu)造函數(shù)初始化對象的基類局部。在執(zhí)行基類構(gòu)造函數(shù)時,對象的派生類局部是未初始化的。實(shí)際上,此時對象還不是一個派生類對象。撤銷派生類對象時,首先撤銷它的派生類局部,然后按照與構(gòu)造順序的逆序撤銷它的基類局部。在這兩種情況下,運(yùn)行構(gòu)造函數(shù)或析構(gòu)函數(shù)時,對象都是不完整的。為了適應(yīng)這種不完整,編譯器將對象的類型視為在構(gòu)造或析構(gòu)期間發(fā)生了變化。在基類構(gòu)造函數(shù)或析構(gòu)函數(shù)中,將派生類對象當(dāng)作基類型對象對待。如果在構(gòu)造函數(shù)或析構(gòu)函數(shù)中調(diào)用虛函數(shù),那么運(yùn)行的是為構(gòu)造函數(shù)或析構(gòu)函數(shù)自身類型定義的版本。18:以下哪些做法是不正確或者應(yīng)該竭力防止的〔〕?!捕囗?xiàng)選擇〕〔2023?搜狗〕A.構(gòu)造函數(shù)聲明為虛函數(shù)B.派生關(guān)系中的基類析構(gòu)函數(shù)聲明為虛函數(shù)C.構(gòu)造函數(shù)調(diào)用虛函數(shù)D.析構(gòu)函數(shù)調(diào)用虛函數(shù)解答:ACD。構(gòu)造函數(shù)和析構(gòu)函數(shù)是特殊的成員函數(shù),在其中訪問虛函數(shù)時,C++采用靜態(tài)聯(lián)編,即在構(gòu)造函數(shù)或析構(gòu)函數(shù)內(nèi),即使是使用虛函數(shù)名〞的形式來調(diào)用,編譯器仍將其解釋為靜態(tài)聯(lián)編的“本類名::虛函數(shù)名〞,因而這樣會與使用者的意圖不符,應(yīng)該盡量防止。虛函數(shù)表指針〔vptr)及虛基類表指針〔bptr)C++在布局以及存取時間上主要的額外負(fù)擔(dān)是由virtual引起的,包括:virtualfunction機(jī)制:用以支持一個有效率的“執(zhí)行期綁定〞;virtualbaseclass:用以實(shí)現(xiàn)屢次出現(xiàn)在繼承體系中的基類,有一個單一而被共享的實(shí)體。19:一般情況下,下面哪些操作會執(zhí)行失敗?〔〕〔多項(xiàng)選擇〕〔2023?搜狗〕classA{public:stringa;voidfl(){printf("HelloWorld");}voidf2(){a="HelloWorld";printf("%s",a.c_str());}virtualvoidf3(){printf("HelloWorld");}virtualvoidf4(){a="HelloWorld";printf("%s",a.c_str());}};A*aptr=NULL;aptr->f1();B.A*aptr=NULL;aptr->f2();C.A*aptr=NULL;aptr->f3();D.A*aptr=NULL;aptr->f4();解答:BCD。因?yàn)锳沒有使用任何成員變量,且fl函數(shù)是非虛函數(shù)〔不存在于具體對象中〕,是靜態(tài)綁定的,所以A不需要使用對象的信息,故正確。在B中使用了成員變量,而成員變量只能存在于對象中:C中f3是虛函數(shù),需要使用虛表指針〔存在于具體對象中);D同C??梢夿CD都需要有具體存在的對象,故不正確。20:請問下面代碼的輸出結(jié)果是什么?classA{public:A(){a=l;b=2;}private:inta;intb;};classB{public:B(){c=3;}voidprint(){cout<<c;}private:intc;};intmain(intargc,char*argv[]){Aa;B*pb=(B*)(&a);pb->print();return0;}解答:1。這里將一個指向B類型的指針指向A類型的對象,由于函數(shù)print并不位于對象中,且print是非虛函數(shù),故執(zhí)行靜態(tài)綁定〔假設(shè)是動態(tài)綁定,那么需要virtual的信息,而對象a中不存在virtual信息,那么執(zhí)行會出錯)。當(dāng)調(diào)用print函數(shù)時,需要輸出c的值,程序并不知道指針pb指向的對象不是B類型的對象,只是盲目地按照偏移值去取,c在類B的對象中的偏移值跟a在類A的對象中的偏移值相等(都位于對象的起始地址處),故取到a的值1。21:sizeof(Test)=4?sizeof(s)=4?sizeof(testl)=1?classTest{inta;staticdoublec;}Test*s;classtest1{};解答:sizeof(Test)=4,因?yàn)閟tatic數(shù)據(jù)成員并不存放在類的對象中。sizeof(s)=4,因?yàn)閟為一個指針。sizeof(testl)=l,因?yàn)榭疹惔笮?。22:以下表達(dá)式在32位機(jī)器編譯環(huán)境下的值為〔〕?!?023???低暋砪lassA{};classB{public:B();virtual?B();};classC{private:#pragmapack(4)inti;shortj;floatk;char1[64];longm;char*p;#pragmapack()};classD{private:#pragmapack(1)inti;shortj;floatk;char1[64];longm;char*p;#pragmapack()};intmain(void){printf("%d\n",sizeof(A));printf("%d\n",sizeof(B));printf("%d\n",sizeof(C));printf("%d\n",sizeof(D));return0;}A.1、4、84、82 B.4、4、82、84C.4、4、84、82 D.1、4、82、82解答:A。類B的大小為4是因?yàn)锽中有指針vptr,可參考圖9-1。23:下面代碼的輸出結(jié)果是什么?intmain(){typedefvoid(*Fun)(void);Baseb;FunpFun=NULL;cout<<"虛函數(shù)表地址:"<<(int*)(&b)<<endl;cout<<"虛函數(shù)表_第―個函數(shù)地址:"<<(int*)*(int*)(&b)<<endl;//InvokethefirstvirtualfunctionpFun=(Fun)*((int*)*(int*)(&b));//Base::f()pFun();pFun=(Fun)*((int*)*(int*)(&b)+1);//Base::g()pfun();pFun==(Fun)*((int*)*(int*)(&b)+2);//Base::h()pFun();return0;}解答:實(shí)際運(yùn)行結(jié)果如下:〔Windows7+VS2023/Linux+GCC4.1.3)虛函數(shù)表地址:001EFC90虛函數(shù)表一第一個函數(shù)地址:00A47874Base::fBase:gBase:h通過這個例如,我們可以看到,我們可以通過強(qiáng)行把&b轉(zhuǎn)成int*,取得虛函數(shù)表的地址,然后,再次取址就可以得到第一個虛函數(shù)的地址了,也就是Base::f(),這在上面的程序中得到了驗(yàn)證〔把int*強(qiáng)制轉(zhuǎn)成了函數(shù)指針〕。圖示如下:&b注意:在上面這個圖中,在虛函數(shù)表的最后多加了一個結(jié)點(diǎn),這是虛函數(shù)表的結(jié)束結(jié)點(diǎn),就像字符串的結(jié)束符’\0’—樣,其標(biāo)志了虛函數(shù)表的結(jié)束。這個結(jié)束標(biāo)志的值在不同的編譯器下是不同的。在Windows7+VS2023下,這個值是NULL。同時類Base的對象大小為4,即類中僅有一個指針vplr(指向虛函數(shù)表)。24:畫出以下類A、B、C、D的對象的虛函數(shù)表。classA{public:virtualvoida(){cout<<"a()inA"<<endl;}virtualvoidb(){cout<<"b()inA"<<endl;}virtualvoidc(){cout<<"c()inA"<<endl;}virtualvoidd(){cout<<"d()inA"<<endl;}};classB:publicA{public:voida(){cout<<"a()inB"<<endl;}voidb(){cout<<"b()inB"<<endl;}};classC:publicA{public:voida(){cout<<"a()inC"<<endl;}voidb(){cout<<"b()inC"<<endl;}};classD:publicB,publicC{public:voida(){cout<<"a()inD"<<endl;}voidd(){cout<<"d()inD"<<endl;}};解答:如下所示:A::aA::bA::cA::dA的對象vptr以上為A類對象的虛函數(shù)表,每個格子記錄一個函數(shù)的地址。B::aB::bA::cA::dB的對象vptr可見,單基繼承時,僅有一個vptr。B類中的函數(shù)a與b覆蓋了A類中的同名函數(shù),故虛函數(shù)表中對應(yīng)位置替換為新函數(shù)的地址。c的對象vptrD的對象可見,單基繼承時,僅有一個vptr。C類中的函數(shù)a與b覆蓋了AD的對象可見,多基繼承時,有幾個基類就有幾個vptr。D類中的函數(shù)a與d覆蓋了B類中的同名函數(shù),故虛函數(shù)表中對應(yīng)位置替換為新函數(shù)的地址。D類中的函數(shù)a與d覆蓋了C類中的同名函數(shù),故虛函數(shù)表中對應(yīng)位置替換為新函數(shù)的地址。25:如下代碼的輸出結(jié)果是什么?classX{};classY:publicvirtualX{};classZ:publicvirtualX{};classA:publicY,publicZ{};intmain(){cout<<"sizeof(X):"<<sizeof(X)<<endl;cout<<"sizeof(Y):"<<sizeof(Y)<<endl;cout<<"sizeof(Z):"<<sizeof(Z)<<endl;cout<<"sizeof(A):"<<sizeof(A)<<endl;解答:1,4,4,8。X類是空的,為什么sizeof(X)=l呢?事實(shí)上,在前面章節(jié)介紹struct的sizeof值時已經(jīng)介紹過原因,這是因?yàn)槭聦?shí)上X并不是空的,它有一個隱晦的1字節(jié),那是編譯器安插進(jìn)去的一個byte。這使得classX的objects得以在內(nèi)存中配置獨(dú)一無二的地址。以下圖給出X、Y、Z的對象布局。derivedclassY事實(shí)上Y和Z的大小受到三個因素的影響:語言本身所造成的額外負(fù)擔(dān)。當(dāng)語言支持虛基類〔virtualbaseclasses)時,就會造成一些額外負(fù)擔(dān)。在子類中,這個額外負(fù)擔(dān)反映在bptr上,即增加了一個指針。編譯器對于特殊情況所做的優(yōu)化處理?,F(xiàn)在的編譯器一般會對空虛基類提供特殊支持〔如VS2023)。在這個策略下,一個空虛基類由于有了一個指針bptr,故不需再像空類一樣占用1個字節(jié),也就是說因?yàn)橛辛顺蓡T,就不再需要原本為了空類而安插的1個byte。Alignment的限制〔如果需要的話),就是字節(jié)對齊。因此,Y和Z的大小都是4字節(jié),其對象內(nèi)僅包含一個bptr,且不需要對齊處理。下面我們討論A的大小。這里需要注意的是:一個虛基類子對象只會在繼承類中存在一份實(shí)體,不管它在繼承體系中出現(xiàn)了多少次。如圖9-2所示,classA的占用空間由下面幾局部構(gòu)成:被大家共享的唯——個classX實(shí)體,大小為1B,目前的編譯器通常都做了優(yōu)化,省去這單單為了占位的1B,故此局部為0;BaseclassY的大小〔為4B)減去“因virtualbaseclassX而配置〞的大小〔此題中為0),故結(jié)果為4B;BaseclassZ的大小〔為4B)減去“因virtualbaseclassX而配置〞的大小〔此題中為0),故結(jié)果為4B;classA自己的大小:0B;前述四項(xiàng)總和,共8B。然后考慮字節(jié)對齊,不需要對齊,故sizeof(A)為8。注意:關(guān)于C++對象模型的更深入研究,可參考《深度探索(:抖對象模型》一書。26:假設(shè)A為抽象類,以下聲明〔〕是正確的?〔2023?迅雷〕A.Afun(int); B.A*p;C.intfun(A) D.AObj;解答:B。抽象類不能定義對象,但是可以作為指針或者引用類型使用。假設(shè)在A和C選項(xiàng)中的A后面加上&或*就是對的。27:抽象類為什么不能實(shí)例化?〔2023?阿里云〕解答:抽象類中的純虛函數(shù)沒有具體的實(shí)現(xiàn),所以沒方法實(shí)例化。28:C++用于類型轉(zhuǎn)換的4個操作符是_,_,_,_?(2023?騰訊〕解答:dynamiccast,constcast,staticcast,reinterpret_cast;reinterpret_cast在引入命名的強(qiáng)制類型轉(zhuǎn)換操作符之前,顯式強(qiáng)制轉(zhuǎn)換用圓括號將類型括起來實(shí)現(xiàn):int*ip;char*pc=(char*)ip;效果與使用reinterpret_cast符號相同。int*ip;char*pc==reinterpret_cast<char*>(ip);const_castconst_cast,顧名思義,將轉(zhuǎn)換掉表達(dá)式的const性質(zhì)。constchar*pc_str;char*pc=const_cast<char*>(pc_str);只有使用const_cast才能將const性質(zhì)轉(zhuǎn)換掉。在這種情況下,試圖使用其他三種形式的強(qiáng)制轉(zhuǎn)換都會導(dǎo)致編譯時的錯誤。類似地,除了添加或刪除const特性,用const_cast符來執(zhí)行其他任何類型轉(zhuǎn)換,都會引起編譯錯誤。29:怎么才能讓ptr指向value?constdoublevalue=0.0f;double*ptr=NULL;解答:強(qiáng)制類型轉(zhuǎn)換,去掉const屬性,如:ptr=const_cast<double*>(value);static_cast編譯器隱式執(zhí)行的任何類型轉(zhuǎn)換都可以由static_cast顯式完成:doubled=97.0;inti=static_cast<int>(d);等價于:doubled=97.0;inti=d;僅當(dāng)類型之間可隱式轉(zhuǎn)換時〔除類層次間的下行轉(zhuǎn)換以外),staticcast的轉(zhuǎn)換才是合法的,否那么將出錯。類層次間的下行轉(zhuǎn)換是不能通過隱式轉(zhuǎn)換完成的,請看下例。classbase{};classchild:publicbase{};base*b;child*c;c=static_cast<child*>(b);//下行轉(zhuǎn)換,正確c=b;//編譯不正確但使用static_cast完成下行轉(zhuǎn)換〔把基類指針或引用轉(zhuǎn)換成子類指針或引用〕,由于沒有動態(tài)類型檢查,所以是不平安的。30:下面程序運(yùn)行后的結(jié)果為〔〕。〔2023?網(wǎng)易游戲〕charstr[]="gladtotestsomething";char*p=str;P++;int*p1=static_cast<int*>(p);p1++;p=static_cast<char*>(p1);printf("%s\n",p);解答:編譯錯誤。在第4章我們介紹了C++類型的指針之間不含有隱式轉(zhuǎn)換(void*除外、const的某些用法為了兼容C語言也可隱式轉(zhuǎn)換),需要顯式轉(zhuǎn)換。故char*不能隱式轉(zhuǎn)換為int*,而僅當(dāng)類型之間可隱式轉(zhuǎn)換時〔除類層次間的下行轉(zhuǎn)換以外),statiC_Cast的轉(zhuǎn)換才是合法的,否那么將出錯。假設(shè)改為:charstr[]="gladtotestsomething";char*p=str;P++;int*pl=(int*)(p);//orint*pl=reiriterpret_cast<int*>(p);pl++;p=(char*)(pi);//orp=reinterpret_cast<char*>(pl);printf("%s\n",p);那么輸出totestsomething。dynamic_cast31:下面〔〕會使這段程序編譯錯誤?〔2023?趨勢科技〕classA{public:A(){}};classB:publicA{public:B(){}};A*pb=newB();Bb;A.A*pa=dynamic_cast<A*>(pb); B.A*pa=static_cast<A*>(pb);C.Aa=static_cast<A>(b); D.Aa=dynamic_cast<A>(b);E.Noneofabove解答:D。用dynamic_cast進(jìn)行轉(zhuǎn)換時,待轉(zhuǎn)換的類型只能是指針或引用,故D錯誤。A中:A*pa=dynamic_cast<A*>(pb);由于pb本身就是A*類型,實(shí)際上不需要轉(zhuǎn)換,事實(shí)上,假設(shè)將A項(xiàng)改為:A*pa=dynamic_cast<B*>(pb);那么編譯錯誤,提示“運(yùn)行時dynamic_cast的操作數(shù)必須包含多態(tài)類類型〞。B中,實(shí)際上也并不需要轉(zhuǎn)換。C中B類繼承自A類,故B類對象b可隱式轉(zhuǎn)換為A類對象,故C正確。dynamic_cast主要用于類層次間的上行轉(zhuǎn)換和下行轉(zhuǎn)換。dynamic_cast運(yùn)算符可以在執(zhí)行期決定真正的類型。如果下行轉(zhuǎn)換是平安的〔也就說,如果基類指針或者引用確實(shí)指向一個派生類對象),這個運(yùn)算符會傳回轉(zhuǎn)型過的指針。如果downcast不平安,這個運(yùn)算符會傳回空指針〔也就是說,基類指針或者引用沒有指向一個派生類對象)。在類層次間進(jìn)行上行轉(zhuǎn)換時,dynamic_cast和static_cast的效果是一樣的;在進(jìn)行下行轉(zhuǎn)換時,dynamic_cast具有類型檢查的功能,比static_cast更平安。32:下述代碼中,假設(shè)調(diào)用函數(shù)func的實(shí)參指向一個B類型的對象,語句1和語句2有什么差異?classB{public:B():b(1){}virtualvoidfoo(){};intb;};classD:publicB{public:D():d(2);intd;};voidfunc(B*pb){D*pd1=static_cast<D*>(pb); //語句1cout<<pd1->b<<endl;cout<<pd1->d<<endl;D*pd2=dynamic_cast<D*>(pb); //語句2cout<<pd2->b<<endl;cout<<pd2->d<<endl;}解答:在上面的代碼段中,如果pb指向一個D類型的對象,即B*pb=newD();func(pb);那么pdl和pd2是一樣的,并且對這兩個指針執(zhí)行D類型的任何操作都是平安的,語句1與語句2后的輸出語句都輸出1與2;但是,如果pb指向的是一個B類型的對象,即B*pb=newB();func(pb);那么pdl將是一個指向B對象的指針,對它進(jìn)行D類型的操作將是不平安的〔如訪問d),輸出d的值時,將會是一個垃圾值,延后了錯誤的發(fā)現(xiàn);而pd2將是一個空指針,對空指針進(jìn)行操作,將會發(fā)生異常,從而能夠更早地發(fā)現(xiàn)錯誤。33:例2中,當(dāng)B中無虛函數(shù)時,會發(fā)生什么?解答:B要有虛函數(shù),否那么語句2會編譯出錯,VS2023會提示“運(yùn)行時dynamic_cast的操作數(shù)必須包含多態(tài)類型〞;static_cast那么沒有這個限制。dynamic_cast運(yùn)行時類型檢查需要運(yùn)行時類型信息,而這個信息存儲在類的虛函數(shù)表〔關(guān)于虛函數(shù)表的概念,詳細(xì)可見本章〕中,只有定義了虛函數(shù)的類才有虛函數(shù)表,沒有定義虛函數(shù)的類是沒有虛函數(shù)表的,故會編譯錯誤。34:語句1與語句2效果是否相同?語句3與語句4呢?classBase1{virtualvoidfl(){cout<<"Base1::f1"<<endl;}};classBase2{virtualvoidf2(){cout<<"Base2::f2"<<endl;}};classDerived:publicBasel,publicBase2{voidf1(){cout<<"Derived::f1"<<endl;}voidf2(){cout<<"Derived::f2"<<endl;}Basel*pb=newDerived;Derived*pDl=dynamic_cast<Derived*>(pD); //語句1Berived*pD2=static_cast<Derived*>(pD); //語句2Base2*pB1=d
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 10吃飯有講究(說課稿)-部編版道德與法治一年級上冊
- 7 湯姆·索亞歷險記(節(jié)選)說課稿-2023-2024學(xué)年六年級下冊語文統(tǒng)編版
- 2025集體土地房屋轉(zhuǎn)讓合同
- Unit 2 My week PB Let's talk (說課稿)-2024-2025學(xué)年人教PEP版英語五年級上冊001
- 2025產(chǎn)品銷售咨詢服務(wù)合同(中介撮合客戶)
- 2025合同模板車位租賃合同范本
- 10吃飯有講究 說課稿-2024-2025學(xué)年道德與法治一年級上冊統(tǒng)編版001
- 個人汽車信貸合同范例
- 鄉(xiāng)村道路改造雨季施工方案
- 重慶不銹鋼支撐施工方案
- T-CACM 1560.6-2023 中醫(yī)養(yǎng)生保健服務(wù)(非醫(yī)療)技術(shù)操作規(guī)范穴位貼敷
- 2024年全國統(tǒng)一考試高考新課標(biāo)Ⅱ卷數(shù)學(xué)試題(真題+答案)
- 人教版小學(xué)數(shù)學(xué)一年級下冊第1-4單元教材分析
- JTS-215-2018碼頭結(jié)構(gòu)施工規(guī)范
- 2024年長沙衛(wèi)生職業(yè)學(xué)院單招職業(yè)適應(yīng)性測試題庫含答案
- 2024山西省文化旅游投資控股集團(tuán)有限公司招聘筆試參考題庫附帶答案詳解
- 出租房房東消防培訓(xùn)
- 2024年度-小學(xué)語文教師經(jīng)驗(yàn)交流
- 加油站廉潔培訓(xùn)課件
- 認(rèn)識比例尺人教版課件
- 2022版義務(wù)教育(生物學(xué))課程標(biāo)準(zhǔn)(附課標(biāo)解讀)
評論
0/150
提交評論