class base {
public:
base(){
cout << "base constructor" << endl;
}
base(const base& rh) {
cout << "base copy constructor" << endl;
}
};
//case 1:
class der : public base {
};
//case 2:
class der : public base {
public:
der(){
cout << "der constructor" << endl;
}
der(const der& rh) {
cout << "der copy constructor" << endl;
}
};
int main() {
der d;
der d1(d);
}
case 1: der d1(d); invokes base class copy constructor whereas in
case-2, base class default constructor and der class copy constructor
is invoked.
Can anyone explain the logic?
In case 1, you get the default copy constructor synthesized by the compiler. This is defined to copy bases and members.
In case 2, you defined your own copy constructor, which does what you tell it to do. You didn't put anything in the initializer list for the base class, so the base is default-constructed[*], same as any other constructor that doesn't explicitly initialize the base. If der had any data members, those would not be copied either.
[*] or one of the other kinds of initialization that amounts to the same thing for non-POD classes. I can never remember those details.
Derived copy constructor will not call base class copy constructor itself by default. When you don't tell the derived class copy constructor to call the base class copy constructor , it will still need to construct the base sub-object, so it will have to call the base default constructor.
But in the example below you , you will see you can add calling to base copy constructor in the member initilize list explicitly of derived class:
class base {
public:
base(int i):m_i(i){
cout << "base constructor" << endl;
}
base(const base& rh) {
m_i = rh.m_i;
cout << "base copy constructor" << endl;
}
private:
int m_i;
};
//case 2:
class der : public base {
public:
der(int i,int j):base(i),m_j(j){
cout << "der constructor" << endl;
}
der(const der& rh):base(rh) {
m_j = rh.m_j;
cout << "der copy constructor" << endl;
}
private:
int m_j;
};
int main() {
der d(1,2);
der d1(d); //d1.m_i = 1, d1.m_j = 2
}
//result
//base copy constructor
//der copy constructor
In the first case, you are not specifying constructors for der, therefore the compiler decides for you, that is copy the data of d to d1 individually, invoking copy constructor of base in the process.
In the second case, you have specified the copy constructor, in which you do not invoke the copy constructor of base yourself. Since you have overridden the copy constructor of der (which tells the compiler to do what you say, not what it wants), the compiler cannot assume you intended to invoke the copy constructor of base too.
Basically there is a call to one copy-con. So in case-2 the copy-con of der is called, and if you like you can use the copy-con of the base in the code. In case one, since you didn't implemented the copy-con in der it calls the function from his base, like it would do with any function that is only implemented in a base class.
Related
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.
#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.
Why does the default copy constructor not call the base constructor of monster but when I include a user-defined copy-constructor in troll it calls the parent (i.e.: monster) constructor?
As I think it works as follow: Create the base object and after that copy the elements inside.
Here is a sample code:
using std::cout;
struct monster {
monster() {
cout << "a monster is bread\n";
}
~monster() {
cout << "monster killed\n";
}
void health() {
cout << "immortal?\n";
}
virtual void attack() {
cout << "roar\n";
}
};
struct troll: monster {
troll() {
cout << "a troll grows\n";
}
~troll() {
cout << "troll petrified\n";
}
protected:
int myhealth { 10 };
};
struct forum_troll: troll {
forum_troll() :
troll { } {
cout << "not quite a monster\n";
}
~forum_troll() {
cout << "troll banned\n";
}
};
int main() {
cout << "a ------\n";
forum_troll ft { };
cout << "copy \n \n";
troll t { ft };
cout << "end \n \n";
}
Why does the default copy constructor not call the Base Constructor but when I include a user-defined copy-constructor it calls the parent constructor?
What gets called is the copy constructor (not the default constructor) for the monster base class. The reason is that before the troll's default-generated copy constructor is called, the copy constructor of its base class (i.e.: monster) is called.
Paying attention to your code:
forum_troll ft { };
troll t { ft };
In the second statement, it is clear that troll's default-generated copy constructor (because you didn't provide any user-defined copy constructor) will be called. It is monster's copy constructor what is called (prior to troll's copy constructor), not its default constructor, because this is what the default-copy constructor does, i.e.: calling the base's copy constructor.
This default behaviour makes sense, since troll's base class is monster (a troll object is a monster object). Therefore, before copy constructing a troll, a monster has to be copy constructed.
When you provide a user-defined copy constructor for troll you are probably not explicitly calling monster's copy constructor and therefore monster default constructor is what gets called.
Im receiving error C2082: redefinition of formal parameter 'rval' in this code while trying to call base copy ctor explicitly:
#include <iostream>
using namespace std;
class Base
{
public:
Base(const Base& rhs){ cout << "base copy ctor" << endl; }
};
class Derived : public Base
{
public:
Derived(const Derived& rval) { Base(rval) ; cout << "derived copy ctor" << endl; }
// error C2082: redefinition of formal parameter 'rval'
};
int main()
{
Derived a;
Derived y = a; // invoke copy ctor
cin.ignore();
return 0;
}
However if do it like this:
Derived(const Derived& rval) { Base::Base(rval) ; cout << "derived copy ctor" << endl; }
then is OK.
Why am I asking this?
according to the answers on StackOwerflow
I do not have to use operator :: to access base copy ctor,
so why do I receive this error?
btw: I'm using visual studio 2010.
I'm having one more question:
Do I have to call base's move constructor in user defined move constructor of derived class?
To call the base constructor you need to put the call in the member initalization list
class Derived : public Base
{
public:
Derived(const Derived& rval) : Base(rval)
{
cout << "derived copy ctor" << endl;
}
};
Assuming that you mean 'move' constructor is the copy constructor - Yes. You will have to call the Base's constructor. Otherwise the definition if the base object within the derived object will not be complete. You can either call a copy constructor or a normal constructor of the base class.
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.