C++面試八股文:static_cast瞭解一下?

2023-06-21 06:00:47

某日二師兄參加XXX科技公司的C++工程師開發崗位第20面:

面試官:C++中支援哪些型別轉換?

二師兄:C++支援C風格的型別轉換,並在C++11引入新的關鍵字規範了型別轉換。

二師兄:C++11引入四種新的型別轉換,分別是static_castdynamic_castconst_cast、和reinterpret_cast

二師兄:static_cast用途最廣泛,除了後面三種型別轉換外,其他的型別轉換都能使用static_cast完成。

二師兄:dynamic_cast主要用於執行時的從父類別指標向子類指標轉換,如果轉換不成功則返回nullptr

#include <iostream>

struct Base
{
    virtual void fun() {}
};
struct Derived : public Base
{
    virtual void fun() override {}
};

int main(int argc, char const *argv[])
{
    Base* b1 = new Base;
    Base* b2 = new Derived;
    Derived* d1 = dynamic_cast<Derived*>(b1);	//d1 == nullptr
    Derived* d2 = dynamic_cast<Derived*>(b2);	//d2 != nullptr
}

二師兄:const_cast主要用於去除指標或參照型別的const屬性。此操作可能會導致未定義的行為,所以需要慎用。

#include <iostream>
void function(const int& val)
{
    int& v = const_cast<int&>(val);
    v = 42;
}
int main(int argc, char const *argv[])
{
    int val = 1024;
    function(val);
    std::cout << val << std::endl;	//val == 42
}
//-----------------------------------------------
#include <iostream>
static constexpr int val_static = 1024;
void function(const int& val)
{
    int& v = const_cast<int&>(val);
    v = 42;
}
int main(int argc, char const *argv[])
{
    function(val_static);
    std::cout << val_static << std::endl;
}
// Segmentation fault

二師兄:reinterpret_cast可以將指標或參照轉換為任何型別的指標或參照。reinterpret_cast實現依賴於編譯器和硬體,可能導致未定義的行為。

#include <iostream>
int main(int argc, char const *argv[])
{
    int i = 42;
    double d = 42.0;
    long* l1 = reinterpret_cast<long*>(&i);
    long* l2 = reinterpret_cast<long*>(&d);
    std::cout << *l1 << std::endl;	//*i1 == 42
    std::cout << *l2 << std::endl;	//*i2 == 4631107791820423168 X86_64 GCC 11.3 
}

面試官:好的。既然已經有C風格的型別轉換,C++11為什麼還要引入新的型別轉換關鍵字?

二師兄:主要有三點,更安全、更靈活、可讀性更好。

面試官:知道什麼是隱式轉換嗎?

二師兄:瞭解一些。隱式轉換是指在表示式中自動進行的型別轉換。比如intdouble相加,會把int先轉為double,然後再進行求和。

面試官:隱式轉換有哪些優勢和缺陷?

二師兄:隱式轉換的優勢是程式碼簡潔。但是有很大缺陷,有些情況隱式轉換的結果和程式設計師的意圖不一致,會導致難以發現的問題。所以在實際專案中一般會新增編譯選項-Werror=conversion來禁止隱式轉換。

面試官:那你知道explicit關鍵字有什麼作用嗎?

二師兄:也是禁止隱式轉換的一個方式:

struct Foo
{
    Foo(int i):val_(i){}
    int val_;
};
struct Goo
{
    explicit Goo(int i):val_(i){}
    int val_;
};
void function1(Foo f){}
void function2(Goo g){}
int main(int argc, char const *argv[])
{
    Foo f = 1024;	//編譯通過,可以把int型別轉換成Foo
    Goo g = 1024;   //編譯失敗,不能把int型別轉換成Goo
    function1(42);  //編譯通過,可以把int型別轉換成Foo
    function2(42);  //編譯失敗,不能把int型別轉換成Goo
}

面試官:如何把一個自定義型別轉換成一個int型別?

二師兄:需要過載operator int()運運算元:

#include <iostream>
struct Foo
{
    Foo(double d):val_(d){}
    double val_;
    explicit operator int(){
        return static_cast<int>(val_);
    }
};

int main(int argc, char const *argv[])
{
    Foo f(42.5);
    int i = static_cast<int>(f);
    std::cout << i << std::endl;	//i == 42
}

面試官:好的,回去等訊息吧。

今天二師兄表現棒極了,晚上必須加個雞腿。感謝小夥伴的耐心閱讀。二師兄的C++面試之旅,明天繼續。

關注我,帶你21天「精通」C++!(狗頭)