經典問題解析五(五十五)

        在面試中有可能會遇到這個面試題,編寫程序判斷一個變量是否是指針。咱們咋一看是否是有點懵逼,咱們能夠想到利用 C 語言中的可變參數函數。在 C++ 中依然是支持的,C++ 編譯器的匹配調用優先級是:一、重載函數;二、函數模板;三、變參函數。咱們能夠將變量分爲兩類:指針和非指針。須要編寫函數的功能是當是指針變量調用時便返回 true,是非指針變量調用時返回 false。ios

        下來咱們就來試着編寫下這個函數面試

#include <iostream>
#include <string>

using namespace std;

template
< typename T >
bool IsPtr(T* v)
{
    return true;
}

bool IsPtr(...)
{
    return false;
}

int main()
{
    int i = 0;
    int* p = &i;
    
    cout << "p is a pointer: " << IsPtr(p) << endl;
    cout << "i is a pointer: " << IsPtr(i) << endl;

    return 0;
}

        咱們利用函數模板和可變參數函數來實現,下來看看編譯結果是否是咱們所指望的ide

圖片.png

        咱們看到已經實現了,因而滿意的交給了面試官。面試官看了下,笑着說你這個程序對通常的數據類型是可行的,對於類類型仍是進行判斷嘛?咱們接着來試下類類型的判斷是否還可行,在程序中添加一個類,再生成一個類對象 t,指向類對象 t 的指針 pt,下來看看編譯結果圖片.png函數

        咱們看到編譯直接報錯了,也就是說對於類對象來講並不行,變參函數沒法解析對象參數。那麼咱們想一想怎麼辦呢,既然不能直接 IsPtr 函數的調用,咱們還能夠利用它的返回值類型的大小來進行判斷,將模板函數的返回值類型設置爲 char,返回一個字符;將全局函數的返回值類型設置爲 int,直接返回 0。再定義一個宏用來判斷函數 IsPtr 的返回值是否是等於 char  類型的大小,若是是則返回 1,不然返回 0。咱們來看看程序學習

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
    }
    virtual ~Test()
    {
    }
};

template
< typename T >
char IsPtr(T* v)
{
    return 'c';
}

int IsPtr(...)
{
    return 0;
}

#define ISPTR(p) (sizeof(IsPtr(p)) == sizeof(char))

int main()
{
    int i = 0;
    int* p = &i;
    
    cout << "p is a pointer: " << ISPTR(p) << endl;
    cout << "i is a pointer: " << ISPTR(i) << endl;
    
    cout << endl;
    
    Test t;
    Test* pt = &t;
    
    cout << "pt is a pointer: " << ISPTR(pt) << endl;
    cout << "t is a pointer: " << ISPTR(t) << endl;

    return 0;
}

        咱們再次編譯看看結果spa

圖片.png

        咱們看到已經編譯經過了,而且也正確進行類對象類型的判斷了。那麼這個面試題咱們就完美的進行回答了。還有一個面試題:若是在構造函數中拋出異常會發生什麼?這便綜合考查到了咱們的基礎知識了,涉及到對象的構造、異常以及其餘方面的知識。那麼在構造函數中拋出異常,最直接的影響就是構造過程會當即中止,那麼當前的對象便沒法生成了。因爲是異常,析構函數一樣也沒法被調用了,對象所佔用的空間會當即收回。那麼在工程項目中的建議是:不要在構造函數中拋出異常,當構造函數可能產生異常時,咱們便要使用二階構造模式指針

        下來咱們仍是以代碼爲例來進行分析對象

#include <iostream>
#include <string>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
        
        throw 0;
    }
    virtual ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test* p = reinterpret_cast<Test*>(1);
    
    try
    {
        p = new Test();
    }
    catch(...)
    {
        cout << "Exception..." << endl;
    }
    
    cout << "p = " << p << endl;

    return 0;
}

        咱們在構造函數先打印函數名,在進行異常的拋出。先將指針 p 指向地址爲 1 處,若是對象生成,那麼便會返回一個地址值。咱們來看看編譯結果圖片

圖片.png

        在拋出異常後,咱們看到 p 的地址仍是爲 1,證實並無對象的生成。咱們應避免在析構函數中拋出異常!!析構函數的異常將致使對象所使用的資源沒法徹底釋放。經過對一些經典問題的學習,總結以下:一、C++ 中依然支持變參函數;二、變參函數沒法很好的處理對象參數;三、利用函數模板和變參函數可以判斷指針變量;四、構造函數和析構函數中不要拋出異常。資源


        歡迎你們一塊兒來學習 C++ 語言,能夠加我QQ:243343083

相關文章
相關標籤/搜索