C++中的隐式转换

3

考虑这个情况:

ClassA obA;
ClassB obB;

obA = obB;

如果ClassA有一个参数类型为ClassB的构造函数,那么在这种情况下它会被调用吗?

如果ClassB中有一个重载的转换运算符 - 将ClassB对象转换为ClassA对象,则将调用运算符方法。如果存在相应的构造函数和重载的转换运算符,哪一个会被调用?我在哪里可以阅读相关信息?


看一下这个问题,它可能会帮到你: https://dev59.com/GkjSa4cB1Zd3GeqPEVE3 - Marco Costa
那不是强制类型转换,而是类型转换。 - molbdnilo
一旦我们解决了OP将operator=与调用构造函数混淆的困惑,这似乎回答了问题:https://dev59.com/ZXM_5IYBdhLWcg3waiiJ - Topological Sort
2个回答

4
如果ClassA有一个以ClassB为参数的构造函数,那么在这种情况下它是否会被调用?
是的,构造函数对隐式类型转换进行考虑: 类对象的类型转换可以由构造函数和转换函数指定。这些转换称为用户定义的转换,用于隐式类型转换(第4条),初始化(8.5)和显式类型转换(第5.4条,第5.2.9条)。
签名为ClassA::ClassA(ClassB)的构造函数称为转换构造函数。在函数调用(例如赋值)期间,构造函数和用户定义的转换运算符被编译成重载集,并选择最佳构造函数进行转换。
如果选择了构造函数:如果源类型是按值传递的类型,则创建源类型(ClassA)的类型的prvalue,该类型已使用目标类型(ClassB)初始化,并用于初始化参数。如果源类型是引用,则使用引用初始化规则
赋值运算符在ClassA中被隐式生成(假设它们没有被覆盖)。它们是:
ClassA& operator=(ClassA const&);
ClassA& operator=(ClassA      &&);

一种隐式转换序列可以选择构造函数或转换函数来转换 ClassB -> ClassA const&ClassB -> ClassA&&。但是,在这种情况下,根据您的方案,转换将无法成功,因为它将是模棱两可的。请考虑:
struct B { operator struct A(); };

struct A {
    A() = default;
    A(B) {}
};

B::operator A() { return A(); }

int main() 
{
    A a; B b;
    a = b; // Error! Ambiguous conversion
}
A::A(B)B::operator A()都可以用于转换,因此转换是不明确的,编译时会出错。

只有在没有歧义的情况下才应用用户定义的转换(参见10.2、12.3.2)。

如果我们将类A中的转换构造函数的签名更改为A::A(B const&),则将使用B 中的转换运算符,因为A 的构造函数需要一个限定词转换(添加const)。
cppreference上有一个主题讨论,您可以了解更多信息。

3
这段代码:
ClassA obA;
ClassB obB;

obA = obB;

这不是你想象中的那样(*)。这段代码:

ClassB obB;
ClassA  obA = obB;

如果满足以下条件,代码将正常工作:

1. ClassA 有一个接受ClassB为参数的构造函数:

class ClassA
{
public:
    ClassA(const ClassB& b)
    {
        //construct *this from b
    }
};

2. ClassB 定义了类型转换运算符:

class ClassB
{
public:
    operator ClassA() const
    {
        //construct ClassA from *this
    }
};

如果在ClassA中有一个带有类型为ClassB的参数的重载转换运算符[...]。
你想说的是构造函数,而不是转换运算符,对吗?你尝试将ClassA转换为ClassB,因此在此情况下来自ClassA的转换运算符是不相关的。

(*)obA构造之后将obB分配给obA,因此对于您的情况,只适用第二个点。您还可以通过添加赋值运算符使其工作:

3.

class ClassA
{
public:
    ClassA& operator=(const ClassB& b)
    {
        //assign b to *this
    }
};

在您的情况下,这将被称为。

关于#1的建议很好。需要注意的是,如果有人尝试同时使用#1和#2,则会遇到循环引用问题。 - AndyG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接