命名空间
变体
操作

用户定义的转换函数

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 

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

目录

[编辑] 语法

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

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

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

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

占位符auto可以在转换类型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++ 标准。

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