This is my code.
When I delete line 11, the output is
A(0)
B(0)
A(1)
about the last line, "A(1) ", why the second constructor of class A is called?
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// B(const B& b) { cout << "B(1)" << endl; }
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
A(0)
B(0)
A(1)
When
B(const B& b) { cout << "B(1)" << endl; }
is commented out/deleted the compiler generates a copy constructor for you. This provided copy constructor will copy all of the members of the class so in this case it will stamp out a copy constructor that looks like
B(const B& copy) : a(copy.a) {}
This is why you see a's copy constructor called.
When you do not comment out/delete
B(const B& b) { cout << "B(1)" << endl; }
You do not copy a because you do not tell it to do so. What the compiler does instead is creates a default initialization for it by transforming the constructor to
B(const B& b) : a() { cout << "B(1)" << endl; }
so the default constructor is called instead of the copy constructor.
The compiler is generating a copy constructor for you, which copies the member a. In order to copy member a, it calls its copy constructor in turn, which prints A(1).
Because object2 is initialized with the implicit copy constructor of B. An implicit copy constructor implicitly copy all the data members of the class, hence the call of the copy constructor of A, which prints "A(1)".
The issue you've run into has to do with thinking commenting out line 11 means you've deleted that constructor.
In C++, there are a couple of constructors that are automatically generated if you ended up using them, even if you didn't declare them yourself. The copy-constuctor, which has the same signature as the commented-out constructor in B, is one of them.
In your case, you end up first calling the default constructor for B, which first constructs it's member A using the default constructor as well. This should give the output you see, where the body of A's copy-constructor is reached before the body of B's because of member initialization ordering.
Then, you make a new object of type B using the assignment operator which implicitly calls the now-generated copy constructor of B. That means A's copy constructor gets called as well, which is a rule in how B's copy-constructor is auto generated. With A's copy-constuctor un-commented, it gets called with the printout.
The compiler for the class B (with the commented copy constructor) defines implicitly the default copy constructor that calls copy constructors for class members.
From the C++ 20 Standard (11.3.4.2 Copy/move constructors)
14 The implicitly-defined copy/move constructor for a non-union class
X performs a memberwise copy/move of its bases and members...
The implicitly defined default copy constructor of the class B looks like
B( const B &b ) : a( b.a )
{
}
Here is a demonstrative program
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// An analogy of the implicitly declared copy constructor
B(const B& b) : a( b.a ){}
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
The program output will be the same as if to remove the copy constructor of class B that corresponds to the implicitly generated copy constructor by the compiler.
A(0)
B(0)
A(1)
Related
I have code like this for example :
class A {
public:
int x;
A() {
std::cout << "Constructor Called !" << std::endl;
}
A(int y):x(y) {
std::cout << "Constructor Param Called !" << std::endl;
}
A(const A& copy) {
std::cout << "Copy Constructor Called !" << std::endl;
}
}
class B {
public:
A value;
//B(const A& val) : value(val){}
}
int main(){
B b { A(22)};
}
If i comment out the B constructor the output is just "Constructor Param Called", but if i uncomment B constructor the output would be "Constructor Param Called" & "Copy Constructor Called". My questions :
Why is the output different if i commented out the constructor ? (I've read about aggregate class & aggregate initialization, is this it ?)
What's the difference between aggregate initialization & direct initialization ?
When you remove the user-provided constructor for B, B becomes an aggregate. So aggregate-initialization is performed where each element of the class is copy-initialized from the elements of the initializer list. Since A(22) is a prvalue of the same class as B's element, copy-elision takes place where the value is stored directly into the object without any calls to the copy-constructor. This is new as of C++17.
When you declare the constructor for B, it is no longer an aggregate, so constructors are considered when you're doing an initialization.
Direct-intialization just means there is no = sign when you're initializing an object. Aggregate-initialization is what takes place when you're initializing an aggregate, and you can take a look at the definition on cppreference for that.
Output:
when B c = a why the output isnt :
cosntructor A
constructor B
copy constructor B
instead of
cosntructor A
copy constructor B
?
========================================================================================
CODE
class A {
public:
A(const A&);
A();
~A();
};
class B : public A {
public:
B(string, int, float, int);
B(const B&);
B();
~B();
};
A::A() { cout << "constructor A\n"; }
A::A(const A& old_str) { cout << "copy constructor A\n"; }
A::~A() { cout << "destructor A\n"; }
B::B() { cout << "constructor B\n"; }
B::B(const B& old_str) { cout << "copy constructor B\n"; }
B::~B() { cout << "destructor B\n"; }
int main()
{
B a;
cout << "\n\n\n";
B c = a;
cout << "\n\n\n";
}
I don t understand when "B c = a" for c aren t called both constructors, of A and B. For B c the output is constructor A constructor B which is fine, why isn t the same happening for "B c = a"
You don't see "copy constructor A" printed because you don't copy construct the A base in the B copy constructor. You can do that in the member-initialiser-list.
B::B(const B& other) : A(other) { cout << "copy constructor B\n"; }
See it live
In this declaration
B c = a;
there is used the defined by the user the copy constructor of the class B.
B::B(const B& old_str) { cout << "copy constructor B\n"; }
The copy constructor implicitly invokes the default constructor of the base class A to create its base class sub-object. As a result you have
cosntructor A
copy constructor B
In fact the copy constructor of the class B
B::B(const B& old_str) { cout << "copy constructor B\n"; }
is equivalent to
B::B(const B& old_str) : A() { cout << "copy constructor B\n"; }
The reason of your confusing is that it seems you think that in this declaration
B c = a;
at first there is created the object c using the default constructor of the class B and then the object a is assigned to the created object c using one more constructor: the copy constructor.
However only one constructor can be used to crate an object and in this case there is used the copy constructor of the class B.
In this declaration
B c = a;
there is neither assignment. a is an initializer that initializers the created object c. You could rewrite this declaration also the following way making it more clear
B c( a );
when B c = a why the output isnt :
Because B c = a; is copy-initialization. Meaning c is created as a copy of object a, using the copy constructor B::B(const B&). So the copy constructor B::B(const B&) is implicitly called by the compiler due to the statement B c = a;. Now, before entering the body of this copy constructor of B, the default constructor A::A() is also implicitly called. Hence you get the output:
constructor A
copy constructor B.
On the other hand, B a; is default initialization which uses the default constructor B::B(). So the default constructor B::B() is implicitly called due to the statement B a;. But before entering the body of this default constructor of B, the default constructor A::A() is also implicitly called. Hence you get the output:
constructor A
constructor B
In this program "A's constructor called " is printing 2 times. My doubt is why "A's constructor called " is not printing with
A b = B::getA();
while getting printed with
A a;
In both the cases we are creating a new object.
Here is my Program:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor called " << endl; }
};
class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
};
A B::a; // definition of a
int main()
{
A a;
A b = B::getA();
return 0;
}
The first constructor is called at program startup, when the static A within B is created.
The second constructor is called within your main when A is allocated on the stack.
There are no more calls to the default A constructor. When you call getA() a copy constructor will be used, which as you have not defined, will be provided by the compiler.
Because getA() calls a copy constructor, which you haven't written, so the default one will be called.
A b = B::getA();
That initialises b using the copy constructor. You're only tracing the default constructor, which isn't used here. If you wanted to trace the copy constructor too, then you'd need to provide one:
A(A const &) { cout << "A's copy constructor called " << endl; }
one contructore is getting called with "static A a" and "A B::a" i.e static initialization of a which is member of class B
during the execution of program in C, C++ all global and static variables initialized first.
Code:
#include<iostream>
using namespace std;
class B{
public:
int b;
B(int x):b(x){
cout << "B() Constructor " << endl;}
B(const B& m):b(m.b){
cout << "B(const B&) copy constructor "<< endl;}
};
class D:public B{
public:
D(int x):B(x){
cout << "D() Constructor " << endl;}
D(const D& n):B(n){ // at this point n should be casted to B object !!?
cout << "D(const D&) copy constructor " << endl;}
operator B(){
cout << "operator B" << endl;
return B(this->b);}
};
int main(){
D ob(1);
cout << "---" << endl;
D oc=ob;
}
Output:
B() Constructor
D() Constructor
---
B(const B&) copy constructor
D(const D&) copy constructor
Questions:
1) if I didn't supply my D copy constructor, the default copy constructor of D must initialize the Base object by calling B copy constructor. My question is what is the argument that copy constructor of B will take ? is it a D object and then it will be casted to a B object ?
2) in the copy constructor of D, I initialized B with a D object n, and there was no calling to the operator B() which proof that the object n of type D didn't get casted to B, so it can be passed as an argument to the B copy constructor. is there any explanation for this behavior ?
First, a cast is something you write in your code to tell the compiler to do a conversion. There are two categories of conversions: implicit and explicit. Implicit conversions will be done when needed, without a cast. Explicit conversions require a cast. What you're talking about here is an implicit conversion, not a cast.
And the answer is that there is an implicit conversion from a reference to a derived type into a reference to a base type. It's that simple: n is a D&, and it can be passed to a function that takes a B& simply by implicitly converting its type.
I'm just supposed to be getting used to basic copy constructors.
I assumed I properly placed copy constructors.
But when I try to compile, I keep getting the error "No matching constructor for initialization of B"
I'm a bit confused.
class A {
int valuea;
public:
A(const A&); // copy constructor
int getValuea() const { return valuea; }
void setValuea(int x) { valuea = x; }
};
class B : public A {
int valueb;
public:
B(int valueb);
B(const B&); // copy constructor
int getValueb() const { return valueb; }
void setValueb(int x) { valueb = x; }
};
int main () {
B b1;
b1.setValuea(5);
b1.setValueb(10);
B b2(b1);
cout << "b2.valuea=" << b2.getValuea() << "b2.valueb=" << b2.getValueb() << endl;
return 0;
}
By declaring B(int) and B(const B &), you have disabled the default constructor that is implicitly placed in the class for you when you have no other constructors because for all the compiler knows, you might not want a default constructor, so it can't make assumptions (see here).
Add the following to B, remembering to initialize the base and members with it:
B(){}
In C++11, this works well:
B() = default;
That will allow B to have a default constructor for use when you declare B b1;
The same thing goes for A, too. You have a copy constructor, so there's no longer any default constructor implicitly placed in for you.