91-100

注:以下問題的部分解析並非全部是自己原創,只是爲了便於以後複習,直接粘貼總結的答案,主要來源是七月在線中的解析部分。https://www.julyedu.com/question/selectAnalyze/kp_id/4/cate/C

1、 以下哪些做法是正確的( )

A 構造函數聲明爲虛函數
B 派生關係中的基類析構函數聲明爲虛函數
C 構造函數調用虛函數
D 析構函數調用虛函數

解釋:選B

虛函數不能是內聯函數,構造函數不能是虛函數。
A選項,構造函數不能聲明爲虛函數,虛函數對應一個vptr(虛函數表指針),可是vptr其實是存儲在對象的內存空間的。如果構造函數是虛的,就需要通過 vptr來調用,可是對象還沒有實例化,也就是內存空間還沒有,無法找到vptr,所以構造函數不能是虛函數。
B選項,析構函數可以聲明爲虛函數,而且有時是必須聲明爲虛函數,是因爲刪除指向派生類的基類指針的時候,如果基類析構函數不是虛函數,派生類的析構函數將不會被執行,其直接後果是內存泄漏。
C選項,在構造函數裏面調用虛函數,編譯不會報錯,但是最好不要這樣做。在調用構造函數時,類裏面的變量可能還被未初始化,虛函數這時可能會訪問內存中未知的區域而產生錯誤,所以最好不要在構造函數裏調用虛函數。
D選項,在析構函數中調用虛函數,最好不要這樣做。對象的析構過程是先析構派生類,然後析構基類;當在基類的析構函數調用虛函數,往往其派生類部分已經被析構,所以也不會呈現出多態。而如果在基類的析構函數中調用純虛函數,編譯器會報錯(一般會報純虛函數名無法解析等錯誤)。

2、 有如下幾個類和函數定義,選項中描述正確的是( )

class A
{
public:
virtual void foo() { }
};

class B
{
public:
virtual void foo() { }
};

class C : public A , public B
{
public:
virtual void foo() { }
};

void bar1(A *pa)
{
B *pc = dynamic_cast(pa);
}

void bar2(A *pa)
{
B *pc = static_cast(pa);
}

void bar3()
{
C c;
A *pa = &c;
B *pb = static_cast(static_cast(pa));
}
A bar1無法通過編譯
B bar2無法通過編譯
C bar3無法通過編譯
D bar1可以正常運行,但是採用了錯誤的cast方法

解釋:選B

static_cast和dynamic_cast都是用於強制類型轉換。dynamic_cast是在運行時遍歷繼承樹,所以,在編譯時不會報錯。但是因爲A和B無關,所以運行時報錯,那麼A和D都是錯誤的。static_cast:編譯器隱式執行的任何類型轉換都可由它顯式完成。
其中對於:
(1)基本類型。如可以將int轉換爲double(編譯器會執行隱式轉換),但是不能將int用它轉換到double(沒有此隱式轉換)。
(2)對於用戶自定義類型,如果兩個類無關,則會編譯出錯(所以B正確),如果存在繼承關係,則可以在基類和派生類之間進行任何轉型,在編譯期間不會出錯。所以bar3可以通過編譯(C選項是錯誤的)。

3、 在Intel CPU上,以下多線程對int型變量x的操作,哪個是原子操作,假定變量的地址都是對齊的( )

A x = y
B x++
C ++x
D x = 1

解釋:選D

原子操作是不可被中斷的一個或一系列操作,原子操作在執行完畢之前不會被任何其它任務或事件中斷。在單處理器系統中,能夠在單條指令中完成的操作都可以認爲是"原子操作",因爲中斷只能發生於指令之間;如果一個操作包含多個cpu指令則不是原子操作。將ABCD四個選項進行反彙編,可以得出:x = y是先將內存中的y讀到寄存器中,然後再將寄存器值賦給x,分爲2步操作;x++是先將內存中的x讀到寄存器中,然後進行+1操作,最後再將寄存器值賦給x,分爲3步操作;++x也是先將內存中的x讀到寄存器中,然後進行+1操作,最後再將寄存器值賦給x,分爲3步操作;x=1是直接對內存進行賦值操作,是單步操作。因此,四個操作中,只有x=1是單條指令完成的,其他都是多條指令完成,因此ABC不是原子操作,D是原子操作。

4、 一般情況下,下面哪些操作不會執行失敗( )

class A
{
public:
string a;
void f1()
{
printf(“Hello World”);
}
void f2()
{
a = “Hello World”;
printf("%s",a.c_str());
}
virtual void f3()
{
printf(“Hello World”);
}
virtual void f4()
{
a = “Hello World”;
printf("%s",a.c_str());
}
};
A A *aptr = NULL; aptr->f1();
B A *aptr = NULL; aptr->f2();
C A *aptr = NULL; aptr->f3();
D A *aptr = NULL; aptr->f4();

解釋:選A

本題考查了成員函數和成員變量的存儲方式:成員函數的代碼存儲在對象空間之外,成員函數是不屬於對象的,而成員變量是屬於對象的。因爲f1()函數沒有使用任何成員變量,所以A正確。在B中f2()函數使用了成員變量a,而成員變量存在於對象中,但是aptr爲NULL,無法使用成員變量a,所以B執行失敗。C選項中,虛函數需要有虛表指針,虛表指針只存在於對象中,所以C執行失敗。D選項結合了B和C中的錯誤。

5、 以下哪個說法正確( )

int func()
{
char b[2]={0};
strcpy(b,“aaa”);
}
A Debug版崩潰,Release版正常
B Debug版正常,Release版崩潰
C Debug版崩潰,Release版崩潰
D Debug版正常,Release版正常

解釋:選A

Debug 通常稱爲調試版本,它包含調試信息,並且不作任何優化,便於程序員調試程序。Release 稱爲發佈版本,它往往是進行了各種優化,使得程序在代碼大小和運行速度上都是最優的,以便用戶很好地使用。Debug 和 Release 並沒有本質的區別,他們只是VC預定義提供的兩組編譯選項的集合,編譯器只是按照預定的選項行動。func函數中數組b越界。Debug 版本會打開編譯調試代碼開關(assert函數會被編譯) ,Release版本關閉條件編譯調試代碼開關(即不編譯assert函數)。因此在Debug版本中會報錯,而release版本不會報錯。

6、 有如下C++代碼,輸出結果爲( )

#include < iostream >
using namespace std;
#define S(a,b) a*b
int main(int argc, char * argv[]){
int s = S(1+2,3+4);
cout << s << endl;
return 0;
}
A 10
B 11
C 20
D 21

解釋:選B

S(1+2,3+4) ==> 1+2*3+4=11

7、 以下程序的輸出結果是( )

main()
{
int i,j,k,a = 3,b = 2;
i = (–a==b++)?–a:++b;
j = a++;k=b;
printf(“i=%d,j=%d,k=%d\n”,i,j,k);
}
A i=2,j=1,k=3
B i=1,j=1,k=2
C i=4,j=2,k=4
D i=1,j=1,k=3

解釋:選D

i = ( --a ==b++)?–a:++b; == > a = 2, a == 2(真),b = 3 , a = 1 , i = 1
j = a++ == > j = a = 1, a = 2
k=b == > k = 3

8、已知(int : 4個字節,float : 4個字節,double : 8個字節)

struct
{
int i;
float j;
double k;
}test1;

union
{
int i;
float j;
double k;
}test2;
請問sizeof ( test1 ),sizeof ( test2 )的值分別爲(不考慮對齊問題)( )
A 16,16
B 16,8
C 8,16
D 8,8

解釋:選B

由於不考慮對齊問題,也就是說所有的對齊都按照1的整數倍對齊。因此,sizeof(test1)的值爲4+4+8=16. 由於union類型的各個成員變量是以同一地址開始存放,因此union類型實際佔用的存儲空間爲其最長的成員變量所佔的存儲空間,因此,sizeof(test2)的值爲8.

9、 a,b爲int型傳入參數,下面四個選項中,不可以實現a,b值互換的是( )

A void swap(int &a, int &b) {int tmp = 0; tmp = b; b = a; a = tmp;}
B void swap(int &a, int &b) {a = a+b; b = a-b; a = a -b;}
C void swap(int a, int b) {int tmp = 0; tmp = b; b = a; a = tmp;}
D void swap(int &a, int &b){a = a+b-(b=a); }

解釋:選C

選項A,函數定義了a和b爲實參的引用,相當於直接在原變量上進行操作,函數中通過tmp變量實現a和b值的互換。
選項B,函數定義了a和b爲實參的引用,函數中a首先賦爲a和b的和,b等於和減去自身,即此時b爲原a的值,a等於和減去b,即得到原b的值。
選項C,函數定義了a和b爲實參的兩個副本,此時僅進行了副本值的交換。
選項D,函數定義了a和b爲實參的引用,表達式中首先計算括號的內容,即b賦值爲a,此時表達式變爲a=a+b-a,而前兩項a和b的值事先壓到操作數棧中,故前兩項的和爲原兩個變量的和,和減去a得到b,即a等於原b的值,實現了值的互換(有些版本中這樣是不能實現互換的)。

10、 下列關於C語言的描述正確的是( )

A C語言的基本單位是語句
B C語言的三種結構的順序、選擇、循環
C C語言是高級語言程序,因此輸入後即可執行
D C語言從第一條可執行語句開始執行

解釋:選B

C語言的基本單位是函數;C程序需要經過編譯和鏈接才能執行;C語言從main函數開始執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章