转换构造函数与转换运算符:优先级

GRB*_*GRB 66 c++ constructor operators type-conversion conversion-operator

在这里阅读关于转换运算符和构造函数的一些问题让我思考它们之间的相互作用,即当存在"模糊"调用时.请考虑以下代码:

class A;

class B { 
      public: 
         B(){} 

         B(const A&) //conversion constructor
         { 
              cout << "called B's conversion constructor" << endl; 
         } 
};

class A { 
      public: 
         operator B() //conversion operator
         { 
              cout << "called A's conversion operator" << endl; 
              return B(); 
         } 
};

int main()
{
    B b = A(); //what should be called here? apparently, A::operator B()
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码显示"被称为A的转换运算符",这意味着调用转换运算符而不是构造函数.如果operator B()从中删除/注释掉代码A,编译器将很乐意切换到使用构造函数(不对代码进行其他更改).

我的问题是:

  1. 由于编译器不认为B b = A();是一个模糊的调用,因此这里必须有某种类型的优先级.这个优先权究竟在哪里确定?(将赞赏C++标准的参考/引用)
  2. 从面向对象的哲学角度来看,这是代码应该表现的方式吗?谁更了解A对象应该如何成为一个B对象,A或者B?根据C++,答案是A- 在面向对象的实践中有什么表明应该是这种情况吗?就我个人来说,无论哪种方式都有意义,所以我很想知道如何做出选择.

提前致谢

Joh*_*itb 50

您进行复制初始化,并且在转换序列中被认为进行转换的候选函数是转换函数和转换构造函数.这些都是你的情况

B(const A&)
operator B() 
Run Code Online (Sandbox Code Playgroud)

现在,这就是你声明它们的方式.重载分辨率从中抽象出来,并将每个候选变换为与调用参数对应的参数列表.参数是

B(const A&)
B(A&)
Run Code Online (Sandbox Code Playgroud)

第二个是因为转换函数是成员函数.这A&是候选者是成员函数时生成的所谓隐式对象参数.现在,参数有类型A.绑定隐式对象参数时,非const引用可以绑定到右值.因此,另一条规则说,当你有两个参数为引用的可行函数时,具有最少 const限定的候选者将获胜.这就是你的转换功能获胜的原因.尝试制作operator Bconst成员函数.你会发现一个含糊不清的地方.

从面向对象的哲学角度来看,这是代码应该表现的方式吗?谁更了解A对象应该如何成为B对象,A或B?根据C++,答案是A - 在面向对象的实践中有什么表明应该是这种情况吗?就我个人来说,无论哪种方式都有意义,所以我很想知道如何做出选择.

对于记录,如果你将转换函数作为const成员函数,那么GCC将选择构造函数(因此GCC似乎认为它B有更多的业务吗?).切换到迂腐模式(-pedantic)以使其进行诊断.


Standardese, 8.5/14

否则(即,对于剩余的复制初始化情况),可以如13.3中所述枚举可以从源类型转换为目的地类型或(当使用转换函数时)到其派生类的用户定义的转换序列. 1.4,通过重载决策(13.3)选择最好的一个.

13.3.1.4

重载决策用于选择要调用的用户定义的转换.假设"cv1 T"是要初始化的对象的类型,使用T类类型,候选函数选择如下:

  • T的转换构造函数(12.3.1)是候选函数.
  • 当初始化表达式的类型是类类型"cv S"时,考虑S及其基类的转换函数.那些未隐藏在S中并且产生其cv非限定版本与T的类型相同或者是其派生类的类型的候选函数.返回"引用到X"的转换函数返回类型X的左值,因此被认为在此选择候选函数的过程中产生X.

在这两种情况下,参数列表都有一个参数,它是初始化表达式.[注意:此参数将与构造函数的第一个参数和转换函数的隐式对象参数进行比较.]

13.3.3.2/3

  • 标准转换序列S1是比标准转换序列S2更好的转换序列,如果S1和S2是引用绑定(8.5.3),并且引用引用的类型是相同类型,除了顶级cv -qualifiers,以及由S2引用的引用引用的类型比由S1引用的引用引用的类型更符合cv.

  • 啊,所以我的问题不是构造函数和运算符之间的优先级,而是每个构造函数和运算符之间的“const”性质。你是对的,将“operator B()”更改为“operator B() const”会导致歧义错误。 (4认同)