Why does a function parameter call a constructor with an argument?

I have this code (stolen by cplusplus.com):

// explicit:
#include <iostream>
using namespace std;

class A {};

class B {
public:
  explicit B (const A& x) {}
  B& operator= (const A& x) {return *this;}
  operator A() {return A();}
};

void fn (B x) {}

int main ()
{
  A foo;
  B bar (foo);
  bar = foo;
  foo = bar;

//  fn (foo);  // not allowed for explicit ctor.
  fn (bar);  

  return 0;
}

      

So obviously the operator fn (foo);

will call the constructor defined in class B, and I don't really understand why. Why would this call the constructor with an argument, I mean things aren't just copied into function parameters when no references are used? If fn (foo);

calls a constructor B (const A& x) {}

, should not fn (bar);

throw an error as there is no constructor for type B argument such as B (const B& x) {}

?

+3


source to share


4 answers


All this because of the fn()

signature:

void fn (B x) {}

      

fn only takes objects of type B and passes them by value.
So what happens when you call fn () with an object of type A?

 A foo;
 fn (foo);  // not allowed for explicit ctor.

      



The compiler tries to find the best match function, a function called fn, and gets type A. ( Overload resolution )
Since there is no such function, it then tries to find the next best match by subjecting the object to the type that fn () accepts.
A conversion constructor usually does the job: B (const A& x) {}


But since it is marked explicit , the compiler cannot do it implicitly.

You need to explicitly specify the object for the compiler to match:

fn ((B)foo);  // Explicit conversion is allowed.

      

+2


source


This is the result of explicit object creation

fn(foo); 

      

implicitly possible, since it fn()

does not accept any object A as a parameter



BUT your foo parameter can actually be used to create an instance of B that matches the fn parameter perfectly , you can prevent this implicit object conversion using the Explicit keyword .

And this is what you are doing here:

 explicit B (const A& x) {}

      

0


source


Well ... B(const B&)

although not explicitly announced, there is. This is because it is one of the special functions for which the compiler has a default:

B()
B(const B&)
B(B&&)
B& operator=(const B&)
B& operator==(B&&)
~B()

      

So B can copy itself.
It cannot implicitly convert the form A, since such a conversion is declared explicit.

fn(B(foo))

would work.

0


source


From the C ++ standard

15 Initialization, which occurs in the form = / of an element with an equal or equal-initializer or condition (6.4), and , as when passing arguments , returns a function, throwing an exception (15.1), handling an exception (15.3), and initializing an aggregate member (8.6 .1) is called copy-initialization . [Note: copy-initialization may cause movement (12.8). - End note]

So for an explicit constructor

explicit B (const A& x) {}

      

this initialization which is actually used to initialize the function parameter

A foo;
B bar = foo;

      

wrong.

This is a direct initialization that can be used with an explicit constructor as shown in your program

A foo;
B bar( foo );

      

0


source







All Articles