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.
Related
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)
#include <iostream>
class A
{
public:
A() { std::cout << "A's constructor called\n"; }
};
class B
{
public:
B() { std::cout << "B's constructor called\n"; }
};
class C: public B, public A // Note the order
{
public:
C() { std::cout << "C's constructor called\n"; }
};
int main()
{
C c;
return 0;
}
Why is the constructor of class A and B called, when a new instance of C is created?
Output is
B's constructor called
A's constructor called
C's constructor called
C is derived from both A and B - so before the constructor for C can be executed, the constructors for A and B must both be completed. If that wasn't the case, then the C constructor could not rely on anything that its base classes provided.
For example, suppose A contained a list of items which is created and filed from a database in its constructor. All instances of A can rely on the list being complete because the constructor has to be finished before the instance is available to the rest of the code. But C is also an A - it derives from it in the same way that "a Ford" is also "A Car" - so it may well want to access that list. When you construct an instance, the base class constructors are automatically called before the derived classes to ensure that everything is ready for action when the derived constructor starts.
For example, change your code slightly:
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B: public A
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
and you will get:
A's constructor called
B's constructor called
C's constructor called
Because the base class constructors are all completed before the derived ones are executed.
Why wouldn't it be? A C contains parts that are a B and an A respectively, and those parts need to be constructed as well. The constructor is the feature that performs this role.
kanishk tanwar's answer has more detail, but I was writing this anyway, so here's a very whistle stop tour of why it's happening to answer your question:
In order to ensure an instance of a class is properly initialised, a constructor for the base types are always called. If you don't specify which constructor you want to call (syntax: C() : B(), A() for C's constructor), the default constructor is used. As a derived class builds on a base class, the base classes have to be constructed first.
In your case you have specified contents to your default constructor, so that is the code that is run when you instantiate C.
I'm kind of confused, because I was sure this should work different. Take a look at this code example:
#include <iostream>
#include <string>
using namespace std;
class base
{
public:
virtual ~base() = default;
};
class derived : public base
{
private:
int a = 0;
int *b = nullptr;
std::string lol;
public:
derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; }
derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; }
virtual ~derived() { cout << "dtor " << lol << endl; delete b; }
virtual void superFunction() { cout << "OMG " << lol << endl; }
};
int main()
{
derived a("a");
derived b("b");
a = b;
}
And the program output with all optimizations off is:
ctor a
ctor b
dtor b
dtor b
I was sure that in this case compiler should generate code that deletes object a and uses copy constructor to create new object. Instead it uses operator= that it implicitly declares.
Can someone explain why? Or point me to C++ standard.
Thanks.
When you write a = b;, compiler calls assignment operator, which will be automatically generated if not present in the code and not marked as deleted. Copy constructor is used only if you try to initialize a new object from another object like this:
derived a("a");
derived b = a;
Also, your code crashes before main returns as it tries to delete b, which points to the same memory from a and from b after a = b; default-assignment.
If you want to delete a with derived destructor after a = b; execution, all you need is copy-and-swap idiom. What is the copy and swap idiom? has a great answer on how to do that in legacy and modern C++. Proper implementation of rule-of-four from that answer will perfectly fit the DRY principle and help you to avoid memory issues. Note the fabulous trick with passing parameter to operator= by value, which makes compiler select the appropriate constructor (copy or move) and allows you to write only four methods instead of all five of them.
#include <iostream>
using namespace std;
class A
{
int x;
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()
{
B b1, b2, b3;
A a = b1.getA();
return 0;
}
Output:
A's constructor called
B's constructor called
B's constructor called
B's constructor called
I am not able to understand how we got the above output and how object declared of 1st class in class 2nd.
I am not able to understand how we got the above output and how object declared of 1st class in class 2nd.
static A a;
is a static member of class B and will be instantiated once for all instances of B.
This happens even before main() is entered, and you're lucky that
cout << "A's constructor called " << endl;
worked well, since static instances aren't guaranteed to be initialized in a specific order (note that std::cout is just another static object instance).
#include <iostream>
using namespace std;
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
~A()
{
cout << "Destructor called" << endl;
}
};
int main()
{
A a; //Constructor called
A b = a; //Constructor not called
return 0;
}
output:
Constructor called
Destructor called
Destructor called
Constructor is called once while the destructor is called twice
What is happning here? Is this undefined behaviour?
The second line invokes what is called a Copy Constructor. Much like lawyers, if you do not have one, one will be provided for you by the compiler.
It is a special type of converter that is invoked when you initialize a variable with another of the same type.
A b(a)
A b = a
Both of these invoke it.
A(const A& a)
{
cout << "Copy Constructor called" << endl;
//manually copy one object to another
}
Add this code to see it. Wikipedia has more info.
In the snippet
A b = a
you are not calling your constructor, but the generated copy constructor:
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
A(const A& rv)
{
cout << "Copy constructor called" << endl;
// If you are not using default copy constructor, you need
// to copy fields by yourself.
this->n = rv.n;
}
~A()
{
cout << "Destructor called" << endl;
}
};
Default Copy Constructor is used to create the second instance.
When you leave the scope the destractor for both objects is called
There are two instances of object A created. One is created by a constructor, the other by the copy constructor. Since you did not explicitly define one, the compiler did the work for you.
Once the app exits, since there are two objects, the destructor method is called twice.
A b=a => A b(a) => This calls the default copy constructor of the class.