conversion constructor called twice - why?

A

Alexander Stippler

Given the following code snippet we get some unexpected behaviour:
//--------------------------------------------------------------------
#include <iostream>

using namespace std;

struct A
{
A() { cerr << "A()" << endl; }
};

struct C;

struct B : public A
{
B();

explicit
B(const B &rhs);

B(const A&rhs);

C
operator()(int from, int to);
};

struct C: public A
{
B r;

operator const B &() const;
};

B::B() { cerr << "B()" << endl; }

B::B(const B &rhs)
{ cerr << "B(const B &rhs)" << endl; }

B::B(const A &rhs)
{ cerr << "B(const A &rhs)" << endl; }

C
B::eek:perator()(int from, int to) { return C(); }

C::eek:perator const B &() const
{ cerr << "operator const B &() const" << endl;
return r;
}

int main()
{
C c;
B b = c; // conversion constructor called twice here - why??
return 0;
}
//--------------------------------------------------------------------

The conversion constructor B(const A &) is called twice when
initializing object b. We would expect a call of
C::eek:perator const B &() const
and then one call of
B::B(const B &).
 
V

Valentin Samko

Alexander said:
struct B : public A
{
explicit
B(const B &rhs);

B(const A&rhs);

};
B b = c; // conversion constructor called twice here - why??
The conversion constructor B(const A &) is called twice when
initializing object b. We would expect a call of
C::eek:perator const B &() const
and then one call of
B::B(const B &).

The call to B::B(const B&) is not happening because that copy constructor is explicit.

Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".

Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
1. "c" is casted to A&
2. a temporary of class B is created from the result via the "B(const A&)" constructor.
3. your "b" is initialised with that temporary.
 
G

Greg

Valentin said:
The call to B::B(const B&) is not happening because that copy constructor is explicit.

Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".

Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
1. "c" is casted to A&
2. a temporary of class B is created from the result via the "B(const A&)" constructor.
3. your "b" is initialised with that temporary.

No, there is no temporary. Two user-defined conversions would be one
more than is allowed. Besides, there is no need of a B temporary since
B has a constructor that accepts an A object directly. So b is
constructed from an A class object (namely, c).

Greg
 
V

Valentin Samko

Greg said:
No, there is no temporary. Two user-defined conversions would be one
more than is allowed. Besides, there is no need of a B temporary since
B has a constructor that accepts an A object directly. So b is
constructed from an A class object (namely, c).

Please read 8.5/14. The right hand side has to be converted to the destination type (B)
first. Only after the rhs is converted, compiler picks the most appropriate constructor.

Besides, no used-defined conversions happen.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top