用户定义的转换是否将派生类类型转换为基类类型?

时间:2020-04-07 02:21:40

标签: c++ language-lawyer

由于阅读了cplusplus标准的一些引号,因此我对从派生类类型转换基类类型感到困惑。此转换是否属于用户定义的转换?

引用一些使我对此感到困惑的报价:

[class.conv] / 1 类对象的类型转换可以由构造函数和转换函数指定。这些转换称为用户定义的转换,用于隐式类型转换...

[class.conv.ctor] / 3
非显式复制/移动构造函数([class.copy])是转换构造函数。

#include <iostream>
struct Base{
   Base() = default;
   Base(Base const&){}
};
struct Derived:Base{
};
int main(){
   Derived d;
   Base b = d; //from d to b, is this a user-defined conversion? Before reading the standard, I think it's not, but now I'm confused about this.
}

因此,根据这些引号,派生类类型对象到基类类型属于用户定义的转换。如果我错过了一些标准写的东西,说将派生类类型转换为基类类型将不属于用户定义的转换,请纠正我。

2 个答案:

答案 0 :(得分:1)

好的,让我们解释一下标准的含义:

类对象的类型转换可以由构造函数和转换函数指定。

现在,让我们假设我们对这些词的含义一无所知。这句话谈论的是一个称为“类型转换”的概念,但具体来说是在谈论“类对象的类型转换”。因此,我们并不是在讨论所有类型转换,而只是其中的一部分。

然后它说“可以指定”,并列出了可以指定它们的几种方法。下句话:

这些转换称为用户定义的转换

请注意,它没有说“这些构造函数”或“这些转换函数”。它说“这些转换”。好吧,唯一被讨论的“转换”是前面讨论的子集:“类对象的类型转换”。因此,该句子可以重新表述为:

[类对象的类型转换]称为用户定义的转换。

因此,我们可以从中看出,类对象可以进行类型转换。可以通过类中的某些内容指定这些转换。这种特殊类型的类型转换称为“用户定义的转换”。

标准在任何时候都没有说构造函数本身是类型转换还是用户定义的转换。构造函数只是指定这种转换的一种方法。

接下来,我们进入[class.conv.ctor]/1

在没有显式指定函数说明符的情况下声明的构造函数指定从其参数类型(如果有)到其类类型的转换。这样的构造函数称为转换构造函数。

好的,我们现在有了“转换构造函数”的定义。确实,给定这个定义,第3段(声明非explicit复制/移动构造函数正在转换构造函数)是多余的;上面的定义清楚地表明了它们。

成为“转换构造函数”是构造函数的属性。 user-defined conversion的过程被阐明,它当然可以调用“转换构造函数”。但是决不表示或暗示这是仅 进程,通过该进程可以调用“转换构造函数”。

因此,复制构造函数是“转换构造函数”这一事实不应解释为表示导致调用复制构造函数的任何内容本身就是用户定义的转换。用户定义的转换会在标准的发生时发生。

在您描述的示例中,发生的情况在[dcl.init]/17.6.2中进行了定义:

否则,如果初始化是直接初始化,或者如果复制是初始化,其中源类型的cv不合格版本与目标的类相同,或为该类的派生类,则构造函数为考虑过的。枚举适用的构造函数([over.match.ctor]),并通过重载解析选择最佳的构造函数。如此选择的构造函数将以初始化器表达式或expression-list作为其参数来初始化对象。如果没有适用的构造函数,或者重载解决方案不明确,则初始化格式不正确。

在此规则中,本身均未声明直接进行任何类型的转换。发生的是目标类型单参数构造函数上的重载解析。重载解决方案的规则在尝试使给定参数适合重载集合中各种参数的可能性时,可以考虑许多转换。但是这些是通用的,与任何函数调用的任何重载解析相关。

就是这样,选择的函数恰好被视为“转换构造函数”,但这并不意味着用户定义的转换已导致该函数被调用。

答案 1 :(得分:0)

此处不考虑用户定义的转换。该标准列出了两种用于复制初始化的情况(语法Base b = d;是一种形式)。他们是

[dcl.init]/17.16.2

否则,如果初始化是直接初始化,或者如果复制是初始化,其中源类型的cv不合格版本与目标的类相同,或为该类的派生类,则构造函数为考虑过的。 ...

[dcl.init]/17.16.3

否则(对于其余的复制初始化情况),可以将用户定义的转换从源类型转换为目标类型... [被使用]。

由于Derived是从Base派生的,因此本例使用前者而不是后者。因此,仅咨询Base的构造函数,而不咨询例如operator Base()中可能定义的任何Derived

相关问题