Порядок литья в С++
Я хотел бы спросить о кастинге на С++.
Я слышал, что когда кастинг неоднозначен, компилятор должен вернуть ошибку,
но, просто для лучшего понимания, я протестировал его, и он этого не сделал, более того, он использовал функции в довольно странном порядке. Когда:
A foo;
B bar = foo;
он использовал оператор литья, но когда я набрал:
bar = static_cast<B>(foo);
он использовал конструктор одиночных аргументов.
Может кто-нибудь объяснить, почему он действует таким образом?
Весь код, который я использовал:
#include <iostream>
#include <typeinfo>
using namespace std;
class B;
class A {
public:
A() {}
A (const B& x);
A& operator= (const B& x);
operator B();
};
class B {
public:
B() {}
B (const A& x) {
cout << "constructor B" << endl;
}
B& operator= (const A& x) {
cout << "Assign B" << endl;
return *this;
}
operator A() {
cout << "Outer B" << endl;
return A();
}
};
A::A (const B& x) {
cout << "constructor A" << endl;
}
A& A::operator= (const B& x) {
cout << "Assign A" << endl;
return *this;
}
A::operator B() {
cout << "Outer A" << endl;
return B();
}
int main ()
{
A foo;
// First one
B bar = foo;
bar = foo;
foo = bar;
// Second one
bar = static_cast<B>(foo);
B bar2 = static_cast<B>(foo);
foo = static_cast<A>(bar);
B bar3 = foo;
A foo2 = bar3;
A foo3 = B();
foo3 = B();
return 0;
}
Edit:
Мой вывод:
Outer A
Assign B
Assign A
Copy constructor B
Copy constructor B
Copy constructor A
Outer A
Outer B
Outer B
Assign A
Ответы
Ответ 1
Причина, по которой ваш компилятор не жалуется на двусмысленность, заключается в том, что ваши конструкторы и операторы присваивания принимают const A/B&
, но operator A()
и operator B()
не объявляются const. Поэтому для преобразования неконстантных объектов компилятор предпочитает operator A/B()
.
Я думаю, что остальное можно объяснить правилами static_cast
conversion, которые в вашем коде сводятся к поведению, как при прямой инициализации, и разрешение перегрузки (поэтому оператор присваивания вызывается только в последнем примере).