【C++11】顯式轉換操做符

隱式類型轉換是C++的一個既好又壞的特性。它給人以方便,但可能形成一些十分隱晦的錯誤。編程


類型轉換提供了一個類型向另外一個類型的構造。函數

class X
{
public:
    operator int() const noexcept
    {
        return 42;
    }
};

void Func(int) {}

int wmain()
{
    X x0;
    X x1;
    Func(x0);
    Func(x1);

    int n = x0 + x1;
    std::cout << n << std::endl; // 84

    return 0;
}

上面的代碼中,X能夠隱式地轉換爲int,因而函數Func能夠接受X類型的參數,x0與x1也能夠用+來作運算。編碼

在實際的編程工做中,一個更常見的例子是,咱們本身定義的字符串類(記爲String)重載了operator const wchar_t*():spa

class String
{
public:
    operator const wchar_t*() const noexcept
    {
        // 函數體
    }
};

從而,若是一個函數須要const wchar_t*類型的參數,就能夠直接傳入一個String實例。code


可是,重載類型轉換也不是萬無一失的。好比,重載operator bool()。對象

重載operator bool()所帶來的問題比較多,以致於不少企業的編碼規範中,都不提倡甚至禁止重載operator bool()。ci

因爲bool屬於算數類型,因此重載了operator bool()的類的實例能夠被用在任何須要算術類型的上下文中。字符串

class Y
{
private:
    int m_;
public:
    explicit Y(int m) :m_{ m } {}
    operator bool() const noexcept
    {
        return (m_ != 0);
    }
};

int wmain()
{
    Y y0{ 12 };
    Y y1{ 25 };
    auto n = y0 + y1; // !!!
    std::cout << n << std::endl;
    return 0;
}

毫無心義的y0 + y1居然(無警告地)編譯經過,並且還經過+產生了一個int,這實在不合理。可能程序做者想要的是Y(38),更可能的是後來維護代碼的人根本沒法知道原做者想幹什麼。隨着代碼的規模變大,這些細微的隱患會越埋越深,或許,未來花費兩天時間找到的BUG就是由它引發的。it


爲了防止這樣的異常狀況,C++11引入了顯式的類型轉換運算符編譯

class X
{
public:
    explicit operator int() const noexcept
    {
        return 42;
    }
};

void Func(int) {}

int wmain()
{
    X x0;
    Func(x0); // 錯誤,不存在從 X 到 int 的(隱式)轉換
    int y = x0; // 錯誤,不存在從 X 到 int 的(隱式)轉換
    Func((int)x0); // 正確1
    Func(int(x0)); // 正確2
    Func(static_cast<int>(x0)); // 正確3

    return 0;
}

用explicit修飾的類型轉換運算符,則相應的類型轉換必須顯式地進行。C式(正確1),函數(正確2),static_cast(正確3)都行。


可是,顯式的類型轉換有一個例外。若是表達式被用做條件,那麼顯式的operator bool()也能夠隱式地進行(僅限轉換到bool)。「被用做條件」即:

  • if、while及do語句的條件部分;

  • for語句頭的條件表達式;

  • 邏輯非運算符(!)、邏輯或運算符(||)、邏輯與運算符(&&)的運算對象;

  • 條件運算符(x ? y : z)的條件表達式。

因爲轉換到bool通常被用做條件,因此operator bool()通常用explicit來修飾。

class K
{
public:
    explicit operator bool() const noexcept
    {
        return false;
    }
};

int wmain()
{
    K k0;
    if (k0) // 正確
    {
        std::cout << "qwer" << std::endl;
    }
    else
    {
        std::cout << "zxcv" << std::endl;
    }
    return 0;
}
相關文章
相關標籤/搜索