使用者定義的轉換函式
目錄 |
[編輯] 語法
轉換函式宣告為非靜態成員函式或成員函式模板,無引數,無顯式返回型別,名稱形式為
operator 轉換型別ID |
(1) | ||||||||
explicit operator 轉換型別ID |
(2) | (C++11 起) | |||||||
explicit ( 表示式 ) operator 轉換型別ID |
(3) | (C++20 起) | |||||||
轉換型別ID是型別ID,但其宣告符中不允許使用函式和陣列運算子[]
或()
(因此轉換為指向陣列的指標等型別需要類型別名/typedef或標識模板:參見下文)。無論typedef如何,轉換型別ID不能表示陣列或函式型別。
儘管在使用者定義轉換函式的宣告中不允許使用返回型別,但宣告語法的decl-specifier-seq可能存在,並且可能包含除type-specifier或關鍵字static
之外的任何說明符。特別是,除了explicit
,還允許使用說明符inline
、virtual
、constexpr
(C++11 起)、consteval
(C++20 起)和friend
(請注意,friend
需要一個限定名:friend A::operator B();)。
當此類成員函式在類X中宣告時,它執行從X到轉換型別ID的轉換
struct X { // implicit conversion operator int() const { return 7; } // explicit conversion explicit operator int*() const { return nullptr; } // Error: array operator not allowed in conversion-type-id // operator int(*)[3]() const { return nullptr; } using arr_t = int[3]; operator arr_t*() const { return nullptr; } // OK if done through typedef // operator arr_t () const; // Error: conversion to array not allowed in any case }; int main() { X x; int n = static_cast<int>(x); // OK: sets n to 7 int m = x; // OK: sets m to 7 int* p = static_cast<int*>(x); // OK: sets p to null // int* q = x; // Error: no implicit conversion int (*pa)[3] = x; // OK }
[編輯] 解釋
使用者定義的轉換函式在隱式轉換的第二階段被呼叫,該階段由零個或一個轉換建構函式或零個或一個使用者定義的轉換函式組成。
如果轉換函式和轉換建構函式都可以用於執行某些使用者定義的轉換,那麼在複製初始化和引用初始化上下文中,過載解析會同時考慮轉換函式和建構函式,但在直接初始化上下文中只考慮建構函式。
struct To { To() = default; To(const struct From&) {} // converting constructor }; struct From { operator To() const {return To();} // conversion function }; int main() { From f; To t1(f); // direct-initialization: calls the constructor // Note: if converting constructor is not available, implicit copy constructor // will be selected, and conversion function will be called to prepare its argument // To t2 = f; // copy-initialization: ambiguous // Note: if conversion function is from a non-const type, e.g. // From::operator To();, it will be selected instead of the ctor in this case To t3 = static_cast<To>(f); // direct-initialization: calls the constructor const To& r = f; // reference-initialization: ambiguous }
可以定義轉換函式將其自身(可能帶有cv限定符)的類(或其引用),將其自身類的基類(或其引用),以及void型別,但不能作為轉換序列的一部分執行,除了在某些情況下透過虛派發
struct D; struct B { virtual operator D() = 0; }; struct D : B { operator D() override { return D(); } }; int main() { D obj; D obj2 = obj; // does not call D::operator D() B& br = obj; D obj3 = br; // calls D::operator D() through virtual dispatch }
它也可以使用成員函式呼叫語法呼叫
struct B {}; struct X : B { operator B&() { return *this; }; }; int main() { X x; B& b1 = x; // does not call X::operatorB&() B& b2 = static_cast<B&>(x); // does not call X::operatorB& B& b3 = x.operator B&(); // calls X::operatorB& }
顯式呼叫轉換函式時,conversion-type-id是貪婪的:它是可能形成conversion-type-id的最長令牌序列(包括屬性,如果有)(C++11 起)
& x.operator int * a; // error: parsed as & (x.operator int*) a, // not as & (x.operator int) * a operator int [[noreturn]] (); // error: noreturn attribute applied to a type
struct X { operator int(); // OK operator auto() -> short; // error: trailing return type not part of syntax operator auto() const { return 10; } // OK: deduced return type operator decltype(auto)() const { return 10l; } // OK: deduced return type }; 注意:轉換函式模板不允許有推導的返回型別。 |
(C++14 起) |
轉換函式可以被繼承,並且可以是虛擬函式,但不能是靜態函式。派生類中的轉換函式不會隱藏基類中的轉換函式,除非它們轉換為相同的型別。
轉換函式可以是模板成員函式,例如 std::auto_ptr<T>::operator auto_ptr<Y>
。有關適用的特殊規則,請參閱成員模板和模板引數推導。
[編輯] 關鍵字
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 296 | C++98 | 轉換函式可以是靜態的 | 它們不能被宣告為靜態的 |
CWG 2016 | C++98 | 轉換函式不能指定返回型別, 但型別存在於轉換型別ID中 |
在轉換函式的宣告說明符中 不能指定返回型別 |
CWG 2175 | C++11 | 尚不清楚[[noreturn]]在 operator int [[noreturn]] ();中是作為 noptr-declarator(函式宣告符)的一部分解析還是轉換型別ID的一部分解析 |
它被解析為 轉換型別ID的一部分 |