命名空间
变体
操作

用户定义的转换函数

来自 cppreference.com
< cpp‎ | language
 
 
C++ 语言
一般主题
流程控制
条件执行语句
if
迭代语句(循环)
for
range-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 规范符
动态异常规范 (直到 C++17*)
noexcept 规范符 (C++11)
异常
命名空间
类型
规范符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储持续时间规范符
初始化
表达式
替代表示
字面量
布尔值 - 整数 - 浮点数
字符 - 字符串 - nullptr (C++11)
用户定义的 (C++11)
实用程序
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
内存分配
特定于类的函数属性
explicit (C++11)
static

特殊成员函数
模板
杂项
 
 

启用从类类型到另一种类型的隐式转换显式转换

内容

[编辑] 语法

转换函数声明类似于非静态成员函数或成员函数模板,没有参数,没有显式返回类型,并且名称为以下形式

operator 转换类型标识符 (1)
explicit operator 转换类型标识符 (2) (自 C++11 起)
explicit ( 表达式 ) operator 转换类型标识符 (3) (自 C++20 起)
1) 声明一个用户定义的转换函数,它参与所有隐式显式转换
2) 声明一个用户定义的转换函数,它仅参与直接初始化显式转换
3) 声明一个用户定义的转换函数,它是条件显式的。

转换类型标识符是一个类型标识符,除了函数和数组运算符 []() 不允许在其声明符中使用(因此转换为诸如指向数组的指针之类的类型需要类型别名/typedef 或一个标识模板:见下文)。无论 typedef 如何,转换类型标识符都不能表示数组或函数类型。

虽然在用户定义的转换函数的声明中不允许返回类型,但声明语法声明说明符序列可能存在,并且可能包含除类型说明符或关键字 static 之外的任何说明符。特别地,除了explicit 之外,说明符inlinevirtual, constexpr(自 C++11 起), consteval(自 C++20 起)friend 也是允许的(注意 friend 需要限定名称:friend A::operator B();)。

当这样的成员函数在类 X 中声明时,它会执行从 X 到 转换类型标识符 的转换。

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

占位符auto 可用于 conversion-type-id,表示推导的返回类型

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>。请参阅成员模板模板参数推导以了解适用的特殊规则。

[编辑] 关键字

operator

[编辑] 缺陷报告

以下行为更改缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 发布的行为 正确行为
CWG 296 C++98 转换函数可以是静态的 它们不能被声明为静态的
CWG 2016 C++98 转换函数不能指定返回类型,
但这些类型存在于 conversion-type-id
返回类型不能在
转换函数的声明说明符中指定
CWG 2175 C++11 不清楚 [[noreturn]]
operator int [[noreturn]] (); 中是作为
noptr-declarator(函数声明符)的一部分还是 conversion-type-id 的一部分解析
它被解析为
conversion-type-id