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

在这里读到关于转换运算符和构造函数的一些问题,让我想起了它们之间的相互作用,即当有一个“模糊”的调用时。 考虑下面的代码:

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; } 

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

我的问题是:

  1. 由于编译器不考虑B b = A(); 作为一个模糊的电话,在这里工作必须有某种优先权。 这个优先顺序究竟在哪里build立? (从C ++标准引用/引用将不胜感激)
  2. 从面向对象的哲学立场来看,这是代码应该如何performance的方式? 谁更了解A对象应该如何成为B对象, A还是B ? 根据C ++,答案是A – 在面向对象的实践中是否有任何事情表明这应该是这种情况? 对我个人而言,这是有道理的,所以我很想知道如何做出select。

提前致谢

您可以复制初始化,而在转换序列中进行转换的候选函数是转换函数和转换构造函数。 这些是你的情况

 B(const A&) operator B() 

现在,这是你申报的方式。 重载parsing从中抽象出来,并将每个候选变换为对应于调用参数的参数列表。 参数是

 B(const A&) B(A&) 

第二个是因为转换函数是一个成员函数。 A&是所谓的隐式对象参数,当候选者是成员函数时产生。 现在,参数有A型。 当绑定隐式对象参数时,非const引用可以绑定到右值。 所以,另一个规则是,当你有两个可行的函数,其参数是引用,那么具有最less的 const限定词的候选者将胜出。 这就是为什么你的转换function获胜。 尝试使operator B成为一个const成员函数。 你会注意到一个模棱两可的问题。

从面向对象的哲学立场来看,这是代码应该如何performance的方式? 谁更了解A对象应该如何成为B对象,A还是B? 根据C ++,答案是A – 在面向对象的实践中是否有任何事情表明这应该是这种情况? 对我个人而言,这是有道理的,所以我很想知道如何做出select。

为了logging,如果你使转换函数成为一个const成员函数,那么GCC会select构造函数(所以GCC似乎认为B有更多的业务呢?)。 切换到迂腐模式( -pedantic ),使其导致诊断。


Standaldese, 8.5/14

否则(即,对于其余的复制初始化情况),可以从源types转换为目标types或者(当使用转换函数时)转换为其派生类的用户定义的转换序列被枚举,如13.3所述。 1.4,最好的是通过重载决议(13.3)来select。

13.3.1.4

重载parsing用于select要调用的用户定义的转换。 假定“cv1 T”是被初始化的对象的types,其中T是类types,候选函数被select如下:

  • T的转换构造函数(12.3.1)是候选函数。
  • 当初始化expression式的types是types“cv S”时,考虑S及其基类的转换函数。 那些没有被隐藏在S中并产生一个types的cv-非限定版本是与T相同的types或者是它的派生类是候选函数。 返回“对X的引用”的转换函数返回typesX的左值,因此被认为在select候选函数的过程中产生X.

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

13.3.3.2/3

  • 如果S1和S2是参考绑定(8.5.3),则标准转换序列S1是比标准转换序列S2更好的转换序列,并且参考引用的types除了顶层cv和S2引用的引用所引用的types比S1初始化的引用引用的types更具有cv限定。

看来MSVS2008对构造select有自己的看法:它在B中调用拷贝构造函数而不pipeA的操作符是否为常量。 所以即使标准指定了正确的行为,在这里也要小心。

我以为MSVS只是在转换运算符之前search合适的构造函数,但是如果从B的构造函数中删除常量字,则会发现它开始调用A的运算符B()。 可能它对于临时对象有一些特殊的行为,因为下面的代码仍然调用B的构造函数:

 A a; B b = a;