命名空间
变体
操作

用户定义的转换函数

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句 (循环)
for
范围 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)
存储期说明符
初始化
 
 

允许从 类类型 到另一类型的隐式转换显式转换

目录

[编辑] 语法

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

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

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

尽管用户定义的转换函数的声明中不允许返回类型,但 声明语法decl-specifier-seq 可以存在,并且可以包含除 类型说明符 或关键字 static 之外的任何说明符。 特别是,除了 explicit 之外,说明符 inlinevirtualconstexpr(自 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&
}

当显式调用转换函数时,转换类型标识 是贪婪的:它是可能形成 转换类型标识 的最长标记序列 (包括属性,如果有)(自 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 可以在 转换类型标识 中使用,表示推导的返回类型

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 转换函数不能指定返回类型,
但类型存在于 转换类型标识
返回类型不能在
转换函数的声明说明符中指定
CWG 2175 C++11 不清楚 [[noreturn]]
operator int [[noreturn]] (); 中是否被解析为
noptr-声明符(函数声明符)或 转换类型标识 的一部分
它被解析为
转换类型标识 的一部分