Alexander_KH
Alexander_KH

Reputation: 189

Implicit casting C++

Consider this case:

ClassA obA;
ClassB obB;

obA = obB;

Is it right, that if ClassA has a constructor which has a parameter of type ClassB, it will be called in this case?

If there is an overloaded casting operator in ClassB - which converts ClassB object to ClassA object, the operator method will be called. If there is corresponding constructor and overloaded casting operator which one will be called? Where can I read about it?

Upvotes: 3

Views: 2223

Answers (2)

David G
David G

Reputation: 96875

Is it right, that if ClassA has a constructor which has a parameter of type ClassB, it will be called in this case?

Yes, constructors are considered for implicit type conversions:

Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

A constructor with the signature ClassA::ClassA(ClassB) is called a converting-constructor. During a function call such as the assignment, constructors and user-defined conversion operators are compiled into an overload set and the best one is chosen for the conversion.

If a constructor is chosen: If the source type is a by-value type, it creates a prvalue of the type of the source type (ClassA) initialized with the type of the destination type (ClassB), and that is used to initialize the parameter. If the source type is a reference, reference-initialization rules are used.


The assignment operators are implicitly-generated in ClassA (assuming they haven't been overriden). They are:

ClassA& operator=(ClassA const&);
ClassA& operator=(ClassA      &&);

An implicit-conversion sequence can choose either a constructor or conversion function to convert from ClassB -> ClassA const& or ClassB -> ClassA&&.

However, in this case, going by your scenario, the conversion would not be able to succeed as it would be ambiguous. Consider:

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
}

Both A::A(B) and B::operator A() are both viable conversion functions to use for the conversion. As such, the conversion is ambiguous and we are given a compile error.

User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2).

If we change the signature of the converting-constructor in class A to A::A(B const&), then the conversion operator in B will be used because the A's constructor requires a qualification-conversion (addition of const).

There is a thread on cppreference where you can learn more.

Upvotes: 4

Mateusz Grzejek
Mateusz Grzejek

Reputation: 12118

This code:

ClassA obA;
ClassB obB;

obA = obB;

is not what you think it is (*). This code:

ClassB obB;
ClassA  obA = obB;

will work (as provided) if:

1. ClassA has constructor, that accepts ClassB as parameter:

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

2. ClassB has defined conversion-to-type operator:

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

If there is an overloaded casting operator in ClassA which has a parameter of type ClassB [...].

You meant constructor, not casting operator, right? You try to convert ClassA to ClassB, so conversion operators from ClassA are irrelevant in this case.


(*) You assign obB to obA after obA's construction, so in your case only second point is applicable. You can also make it work by adding assignment operator:

3.

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

which would be called in your case.

Upvotes: 3

Related Questions