華爲C/C++筆試題3

1. 找錯

#define MAX_SRM 256

DSN get_SRM_no()
{
    static int SRM_no;
    int I;
    for(I=0;I<MAX_SRM;I++,SRM_no++)
    {
        SRM_no %= MAX_SRM;
        if(MY_SRM.state==IDLE)
        {
            break;
        }
    }
    if(I>=MAX_SRM)
        return (NULL_SRM);
    else
        return SRM_no;
}

 

答:
(1). SRM_no沒有賦初值
(2). 由於static的聲明,使該函數成爲不可重入(即不可預測結果)函數,因爲SRM_no變量放在程序的全局存儲區中,每次調用的時候還可以保持原來的賦值。這裏應該去掉static聲明。

 

2. 寫出程序運行結果

int sum(int a)
{
    auto int c=0;
    static int b=3;
    c+=1;
    b+=2;
    return(a+b+C);
}
  
void main()
{
    int I;
    int a=2;
    for(I=0;I<5;I++)
    {
        printf("%d,", sum(a));
    }
}

答:8,10,12,14,16

該題比較簡單。只要注意b聲明爲static靜態全局變量,其值在下次調用時是可以保持住原來的賦值的就可以。

 

3.

int func(int a)
{
    int b;
    switch(a)
    {
        case 1: b=30;
        case 2: b=20;
        case 3: b=16;
        default: b=0;
    }
    return b;
}

 

則func(1)=?

答:func(1)=0,因爲沒有break語句,switch中會一直計算到b=0。

 

4.

int a[3];
a[0]=0; a[1]=1; a[2]=2;
int *p, *q;
p=a;
q=&a[2];

 

則a[q-p]=?

答:a[q-p]=a[2]=2;這題是要告訴我們指針的運算特點

 

5.  定義 int **a[3][4], 則變量佔有的內存空間爲:_____

答:此處定義的是指向指針的指針數組,對於32位系統,指針佔內存空間4字節,因此總空間爲3×4×4=48。

 

6. CObject類中的析構函數爲什麼是虛函數

面試SE時,很多公司喜歡問到虛函數相關。MFC類庫中,CObject類的重要性不言自明的。在CObject的定義中,我們看到一個有趣的現象,即CObject的析構函數是虛擬的。

在AFX.H中,CObject的定義:

class CObject
{
public:
     // Object model (types, destruction, allocation)   
     virtual CRuntimeClass* GetRuntimeClass() const;
     virtual ~CObject(); //virtual destructors are necessary
      
      
};

 

爲什麼MFC的編寫者認爲virtual destructors are necessary (虛擬的析構函數是必要的)?
在著名的VC教程 "精通Visual C++ for Windows 95/NT"(電子工業版, 1997年5月版,胡儉,丘宗明等著)第99頁中有這樣一段話:
“如果CObject的析構函數不是虛擬的,派生類就不會自動地得到虛擬的   析構函數,當對象撤消時就會帶來問題——只有當前類的析構函數得到調用而基類的析構函數就得不到調用...”  
我認爲這段解釋是這本很不錯的書中一個不應出現的嚴重錯誤。其意思是說:
若:

class CBase
{
   public:
      ~CBase() {   };
    
};

class CChild : public CBase
{
   public:
      ~CChild() {   };
    
};

main()
{
   Child c;
    
   return 0;
}

 

上段代碼在運行時,當棧框中的自動對象 c 被撤消時,只調用~CChild(), 而不調用~CBase()。
我想但凡對C++繼承性理論有所瞭解的人都會立刻指出這是錯誤的。
由於在生成CChild對象c時,實際上在調用CChild類的構造函數之前必須首先 調用其基類CBase的構造函數,所以當撤消c時,也會在調用CChild類析構函數之後,調用CBase類的析構函數(析構函數調用順序與構造函數相反)。也就是說,無論析構函數是不是虛函數,派生類對象被撤消時,肯定會依次上調其基類的析構函數。

那麼爲什麼CObject類要搞一個虛的析構函數呢?

仍以上面代碼爲例,如果main()中有如下代碼:
...
CBase * pBase;
CChild c;
pBase = &c;
...

那麼在、當pBase指針被撤消時,調用的是CBase的析構函數還是CChild的呢? 顯然是CBase的(靜態聯編)。但如果把CBase類的析構函數改成virtual型,當 pBase指針被撤消時,就會先調用CChild類構造函數,再調用CBase類構造函數。

在這個例子裏,所有對象都存在於棧框中,當離開其所處的作用域時,該對象 會被自動撤消,似乎看不出什麼大問題。但是試想,如果CChild類的的構造函數在堆中分配了內存,而其析構函數又不是virtual型的,那麼撤消pBase時,將不會 調用CChild::~CChild(), 從而不會釋放CChild::CChild()佔據的內存,造成內存泄露。

而將CObject的析構函數設爲virtual型,則所有CObject類的派生類的析構函數都將 自動變爲virtual型,這保證了在任何情況下,不會出現由於析構函數未被調用而導致 的內存泄露。這纔是MFC將CObject::~CObject()設爲virtual型的真正原因。

注意:析構函數可以爲virtual型,構造函數則不能。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/ssfp8762/archive/2009/05/08/4162063.aspx

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