class A {};
class B { public: B (A a) {} };
A a;
B b=a;
I read this from http://www.cplusplus.com/doc/tutorial/typecasting/ . It says this is a implicit type conversion. From class A to class B.
I want to ask, is this also an example of copy constructor?
Thanks.
No, it's not a copy constructor. A copy constructor copies one object of one type into another of the same type:
B::B(const B& b)
{
// ...
}
As a side note, if you need a copy constructor then you also need a destructor and an assignment operator, and probably a swap function.
What B::B(A) is is a conversion function. It's a constructor that allows you to convert an object of type A into an object of type B.
void f(const B& obj);
void g()
{
A obja;
B objb = obja;
f(obja);
}
No, A copy constructor has the form
class A
{
public:
A(const A& in) {...}
}
No, a copy constructor is called when you create a new variable from an object. What you have there is two objects of different types.
The line B b = a; implies that a copy constructor is used, as if you had typed B b = B(a); or B b((B(a)));. That is, the compiler will check whether B has an accessible (public) copy constructor - whether user-defined or the default one provided by the compiler. It doesn't mean, though, that the copy constructor has to be actually called, because the language allows compilers to optimize away redundant calls to constructors.
By adding a user-defined copy constructor to B and making it inaccessible, the same code should produce a compiler error:
class A {};
class B {
public:
B (A ) {}
private:
B (const B&) {} // <- this is the copy constructor
};
A a;
B b=a;
For example, Comeau says:
"ComeauTest.c", line 10: error: "B::B(const B &)" (declared at line 6), required
for copy that was eliminated, is inaccessible
B b=a;
^
Related
Given base class A and derived class B, A has deleted move constructor:
class A {
public:
A() {}
A(const A&) = default;
A(A&&) = delete;
};
class B : public A
{
};
In such case, the following function does not compile because of deleted move constructor:
A f() {
A a;
return a;
}
but the similar function for B does not report any error:
B g() {
B b;
return b;
}
Does it mean that move constructor in B is not deleted? I want to know what is the rule in the standard.
The move constructor in B is deleted, but does not participate in overload resolution. According to cppreference:
The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following is true:
T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors);
T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors);
T has direct or virtual base class or a non-static data member with a deleted or inaccessible destructor;
T is a union-like class and has a variant member with non-trivial move constructor.
A defaulted move constructor that is deleted is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).
The second bullet point applies: B has a direct base class, A, with a deleted move constructor. So B's implicitly-declared move constructor is defined as deleted.
However, when the return statement is evaluating which constructor of B to use, the deleted move constructor is not considered but the valid copy constructor is.
The move constructor of B is deleted, as already answered by #Nathan Pierson.
The reason that you can return the local b from g is, as explained there, that the implicitly deleted move constructor of B is not participating in the overload resolution, thus the compiler selects the default copy constructor of B.
To prove the above take a look at the following code, adding a moveable only member into B:
class B : public A {
std::unique_ptr<int> ptr;
public:
B() {}
// needs this to compile:
// B(B&& b): A(b), ptr(std::move(b.ptr)) {}
};
B g() {
B b;
// now this would fail
// B doesn't have a default move ctor
// (it is implicitly deleted because of A)
// and the default copy ctor is not valid
return b;
}
Hisenter link description here
enter link description here
I have this example
struct B { B(); };
struct D : B { };
D d{ B() }; // what happens here? or why it's well-formed
This is an aggregate initialization, but I can't understand how d is constructed? Does the compiler generates implicitly a copy constructor with this signature D::D(const D&) or D::D(const B&) or what? It's clear that the compiler does not generate D::D(const D&) because const D& = B() is ill-formed. So this means it generates a copy constructor D::D(const B&)?
Now what would happen if I inherits constructors from B:
struct B { B(); };
struct D : B { using B::B; };
D d{ B() }; // why it's ill-formed?
One said to me that the default copy constructor of B which is B::B(const B&) is inherited into D but it's excluded from the set of candidates, that's why it's ill-formed. Is that true?
Can the compiler generates a default copy constructor that takes reference to different class type?
By definition, no. A constructor that accepts an object of another type is not a copy constructor. It would be a converting constructor.
No such converting constructor is implicitly generated.
This is an aggregate initialization, but I can't understand how d is constructed?
No constructor of the enclosing class is called in aggregate initialisation. The sub objects are initialised directly.
D is an aggregate with a base class of type B. Aggregate initialisation is used to initialise this base sub object.
It's clear that the compiler does not generate D::D(const D&) because const D& = B() is ill-formed.
Former cannot be deduced from the latter. In fact, there is a (trivial) D::D(const D&) which you can prove by attempting copy initialisation:
D d1{};
D d2(d1); // works
That said, a trivial constructor is a concept for the abstract machine, and the compiler doesn't have to generate anything in practice.
Now what would happen if I inherits constructors from B
struct D : B { using B::B; };
D d{ B() }; // why it's ill-formed?
Having inherited constructors disqualifies the class from being an aggregate and hence aggregate initialisation does not apply. List initialisation will attempt to call a constructor, but no converting constructor exists.
class A {
public:
A() {}
A(const A& a) { cout << "A::A(A&)" << endl; }
};
class B {
public:
explicit B(A aa) {}
};
int main() {
A a;
B b(a);
return 0;
}
Why does it print "A::A(A&)"?
When was the copy constructor for "A" called? And if the code calls the copy constructor, why can I remove the copy constructor without creating a compilation error?
B(A aa) takes an A by value, so when you execute B b(a) the compiler calls the copy constructor A(const A& a) to generate the instance of A named aa in the explicit constructor for B.
The reason you can remove the copy constructor and have this still work is that the compiler will generate a copy constructor for you in cases where you have not also declared a move constructor.
Note: The compiler generated copy constructor is often not sufficient for complex classes, it performs a simple member wise copy, so for complex elements or dynamically allocated memory you should declare your own.
ยง 15.8.1
If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly.
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy
constructor is defined as deleted; otherwise, it is defined as defaulted (11.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a user-declared destructor or assignment operator.
Why the copy happens
Look at your class B c'tor:
class B {
public:
explicit B(A aa) {}
};
You receive A by value, triggering a copy during the call.
If you would have change it to (notice A & aa):
class B {
public:
explicit B(A & aa) {}
};
There wouldn't be any copy...
Default copy constructor
When you remove the c'tor, the compiler generates one for you when it can trivially do so:
First, you should understand that if you do not declare a copy
constructor, the compiler gives you one implicitly. The implicit
copy constructor does a member-wise copy of the source object.
The default c'tor is equivalent to:
MyClass::MyClass( const MyClass& other ) :
x( other.x ), c( other.c ), s( other.s ) {}
I'd like to assign the object of type B to object of type A, but i don't know why it works with different types for the assignment?
#include <stdio.h>
class B
{
public:
B()
{
printf("B default constructor.\n");
}
};
class A
{
public:
A()
{
printf("A Default constructor.\n");
}
A(B const& b) // if add the tag "explicit" for the constructor, it will not work...
{
printf("User constructor.\n");
}
A(const A& a)
{
printf("copy-constructor.\n");
}
void get(){printf("A::get\n");}
};
int main()
{
A a = B(); // What's the meaning to assign object of type B to object of type A?
Why it works with above line?
How it works when do this?
a.get();
}
Every constructor that can be called with a single argument defines an implicit conversion to a class type. So the constructor:
A(B const& b)
is a conversion constructor. If this type of conversion is not useful, you've found the answer: declaring it as explicit can prevent it:
explicit A(B const& b)
I think your problem comes from thinking it is assignment. But A a = B(); is initialization. a is not first created with default constructor and then assigned to, it is directly constructed. And while I don't have the standard reference handy, if you don't have the constructor but have the assignment operator overload, that line will not compile, because it is not assignemnt, it needs the right constructor. To have assignment, try
A a;
a = B(); // actually assigns A(B()) implicitly if no operator= overload
If all data members of a class can be assigned, then objects of the class can be assigned, so that's why a = A(); works without adding any code.
If you want to block the implicit conversion, make the constructor explicit (example in the other answer).
I stumbled across a question that I never thought about before.
Here it is:
each object's (listed in the initialization list) "constructor" will be triggered.
class B
{
public:
B() { cout<<"B Con\n";}
B(const B &b) { cout<<"B Copy Con\n";}
};
class A
{
public:
A(B &b):_m(b) { cout<<"A Con\n";}
A(const A &a):_m(a._m) { cout<<"A Copy Con\n";}
private:
B _m;
}
main()
{
B b;
A a(b);
}
then I got the output as follows:
B Con
B Copy Con
A Con
According to the output, I think, 'A a(b)' triggered B's copy constructor.
If I got right, then that means 'A(B &b):_m(b)' triggers B's copy constructor.
Why not constructor but copy-constructor?
The reason is when you call
_m( whatever )
then the copy constructor
B(const B &b)
is the only one that could match the parameter list. You pass it one parameter and that parameter is of type class B.
Copy constructor is not something super special - it is just a parameterized constructor that will be invoked via the initialization list once the parameter list matches.
Because you're telling the compiler to initialize _m with b, how would that not call the copy constructor?
The answer lies in the A(B &b):_m(b) You are instantiating B _m with the copy constructor.
If instead you did A(B &b):_m() it would use the default constructor.
A(B &b):_m(b) { cout<<"A Con\n";}
Here _m(b) causes invocation of B(const B&) which is B's copy-constructor. That is why, it first prints B Copy Con when initializing _m, then it enters into A's constructor body, and prints A Con. That explains it all.