簡體   English   中英

C++中從用戶定義類型到基本類型的隱式轉換

[英]Implicit conversion from user-defined type to primitive type in C++

我能夠找到大量有關從 int 到用戶定義類型的隱式轉換的信息。 即,如果構造函數采用 int 作為其參數,並且沒有以“顯式”開頭,則可能會發生隱式轉換。

如果我希望我的類隱式轉換int 怎么辦?

例如,需要在 SimpleClass 內部或外部添加什么函數,以便 main 函數編譯並輸出“1”到控制台? (看評論)

#include <iostream>

class SimpleClass
{
private:
    int m_int;
public:
    SimpleClass(int value)
    : m_int(value) {}
};

int main(int argc, const char * argv[])
{
    SimpleClass simpleclass(1);
    int i = simpleclass; // does not complile
    std::cout << i << std::endl; // should output "1" to the console
    return 0;
}

隱式轉換可以通過兩種方式定義:

  • 非顯式單參數構造函數。
  • 非顯式轉換函數(又名轉換運算符),N3337 12.3.2

后者允許定義從類類型到原始類型的轉換。 只需添加

class SimpleClass {
   // ...
   operator int() const;
};

SimpleClass::operator int() const
{
   return m_int;
}

技術。

可以通過operator T成員函數執行到(幾乎)任何類型T轉換。

默認情況下,它是隱式調用的,如果您將其聲明為const它也可以在const對象上調用。

因此:

struct MyType
{
    operator int() const { return 1; }
};

問題…

對基本類型的隱式轉換允許所有內置運算符自由發揮,包括

  • 算術運算符。
  • 布爾運算符。
  • 關系運算符。

所以你最好確保所有這些都按照你想要的方式工作

這可能是很多工作!

對於涉及您的類型實例的調用,重載解析也存在潛在問題。

簡而言之,隱式轉換為int 、指針或任何內置類型的成本通常高於其價值。

一個值得使用的例外是在庫中大量使用類時。

你能做些什么。

避免隱式轉換,但提供顯式轉換。

最好的通用顯式轉換是,恕我直言,一個命名成員函數。

一個替代方法是一個以關鍵字explicit為前綴的operator T ,它在 C++11 和更高版本中支持這種用法(在 C++03 中它只能用於構造函數)。

如果您希望通過<<輸出表現得好像執行了隱式轉換,那么只需定義一個operator<<

類似地,對於隱式轉換似乎是通用解決方案的其他情況:只需定義適合該特定情況的內容,並避免引入通用隱式轉換。


為了提供到內置類型的隱式轉換,同時避免內置運算符的“免費”,您可以使用模板化類型轉換,例如:

#include <iostream>

template< class A, class B > struct Is_t_;

template< class Type > struct Is_t_<Type, Type> { using T = void; };

template< class A, class B >
using If_is_ = typename Is_t_<A, B>::T;

struct Bad_string
{
    operator const char* () const { return "666!"; }
    Bad_string( char const* = 0 ) {}
};

auto operator==( Bad_string const&, Bad_string const& )
    -> bool
{ return true; }

struct Good_string
{
    template< class Type, class Enabled_ = If_is_<const char*, Type>>
    operator Type() const { return "42 :)"; }

    Good_string( char const* = 0 ) {}
};

auto operator==( Good_string const&, Good_string const& )
    -> bool
{ return true; }

#if defined( DO_GOOD )
    using String = Good_string;
#elif defined( DO_BAD )
    using String = Bad_string;
#else
#   error "Define either DO_GOOD or DO_BAD, please."
#endif

auto main() -> int
{
    String a, b;
    (void) (a == "alfalfa");        // Errs for Bad_string
    (void) (a + 1);                 // Compiles for Bad_string.
}

具有諷刺意味的是,當定義DO_GOOD時,此代碼會導致 Visual C++ 2015 update 1 編譯器崩潰,即所謂的“ICE”(內部編譯器錯誤)。

該編譯器的解決方法是將If_is_定義為

template< class A, class B >
using If_is_ = std::enable_if_t< std::is_same<A, B>::value >;

要允許您的類轉換為int ,請實現

operator int() const
{
  return m_int;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM