Michał Ziobro
Michał Ziobro

Reputation: 159

Order of casting in C++

I would like to ask about casting in C++. I heard that when casting is ambiguous compiler should return an error, but, just for better understanding, I tested it and it didn't, moreover, it used functions in quite weird order. When:

A foo;
B bar = foo;

it used casting operator, but when I typed:

bar = static_cast<B>(foo);

it used single argument constructor.

Can anyone explain why it acts in this way?

The whole code which I used:

#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:

My output:

Outer A
Assign B
Assign A
Copy constructor B
Copy constructor B
Copy constructor A
Outer A
Outer B
Outer B
Assign A

Upvotes: 14

Views: 936

Answers (1)

acs
acs

Reputation: 84

The reason your compiler does not complain about ambiguity is that your constructors and assignment operators take a const A/B&, but operator A() and operator B() are not declared const. For the conversion of non-const objects, the compiler therefore prefers operator A/B().

I think that the rest can be explained with the rules of static_cast conversion, which in your code amounts to behavior as in direct initialization, and overload resolution (which is why the assignment operator is only called in the last example).

Upvotes: 3

Related Questions