Reputation: 8777
I do not understand how this code is compiling. Can somebody please explain what is going on in there.
#include <iostream>
using namespace std;
class B
{
public:
B(const char* str = "\0") //default constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob = "copy me"; //why no compilation error.
return 0;
}
The optput is: Constructor called
P.S.: I could not think of a more apt title than this, Anyone who can think of a better title, please modify it.
Upvotes: 0
Views: 283
Reputation: 5316
Edit: after discussion with Kerrek SB I got a copy of the C++11 standard. I was wrong, there's a temporary. I'm editing this reply to reflect my newly acquired understanding.
15 years ago I knew C++ extremely well (that was around the time the first standard was to be released). I haven't used it since late 1998 so I have forgotten a lot and I know almost nothing of the recent standards.
The code is correct.
B ob = "copy me"; //why no compilation error.
There's no error. This is parsed as a declaration of an initialized variable. B
is the type, ob
the name of the variable, "copy me"
the initializer.
The initializer is of type const char*
and there is, in class B, a constructor that takes a const char*
typed single argument. That constructor is not declared restricted by explicit
and therefore can be used in this context.
Either a temporary object is created and then copied (you see both lines printed out) or the copy is elided and only the conversion constructor is called to construct directly at the destination (you see only one line printed). The standard explicitly allows this even if the copy constructor has side effects.
The program execution will print Constructor called to stdout. It may or may not then also print Copy constructor called. There is no error.
Upvotes: -1
Reputation: 817
This is because of implicit conversion. Add a Explicit to your Default constructor and try. it will Fail to compile.
Upvotes: 0
Reputation: 267
If you add keyword explicit to your default constructor to prevent implicit conversion. Then it will not compile. Your answer is implicit conversion.
Upvotes: 7
Reputation: 24134
That's because of implicit conversion of the assignment statement to
B ob("copy me");
Try this to fail compilation (look at the explicit
keyword):
#include <iostream>
using namespace std;
class B
{
public:
explicit B(const char* str = "\0") //default constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob = "copy me"; //why no compilation error.
return 0;
}
Upvotes: 4
Reputation: 38173
Because this
B ob = "copy me";
invokes the copy constructor, which takes argument const B &b
and you class B
has a constructor
B(const char* str = "\0")
which is not defined as explicit
.
The compiler is allowed to make one implicit conversion.
So, what happens here:
B ob = "copy me";
is:
B
, using the provided const char* str
- this is allowed, since class B
has constructor, which takes one argument and is not defined as explicit
. In other words, all objects with type B
can be constructed from a const char*
ob
, using the temp object, created in 1.
.Upvotes: 7
Reputation: 726987
[it shouldn't compile because] the specified line does not match in data types
There is no compilation error because there exists a constructor of B
that takes const char*
as an argument, allowing for conversion between const char*
and B
.
Upvotes: 3
Reputation: 477514
The type of "copy me"
is char const[8]
, which decays to char const *
. Since the default constructor is not explicit
, "copy me"
can be implicitly converted to B
, and thus ob
can be copy-constructed from that implicitly converted, temporary B
-object.
Had the default constructor been declared explicit
, you would have had to write one of the following:
B ob1 = B("copy me");
B ob2("copy me");
Had the copy constructor also been declared explicit
, you would have had to say one of these:
B ob3(B("copy me"));
B ob4("copy me");
In practice, all copies will be elided by any half-decent compiler, and you always end up with a single default constructor invocation.
Upvotes: 10