Why are copy constructors of base classes not implicitly called? [duplicate] - c++

This question already has answers here:
Why aren't copy constructors "chained" like default constructors and destructors?
(3 answers)
Closed 3 years ago.
From my understanding, when creating an object of a derived class the base class constructor get's automatically called (in case a one without parameters exists). This seems to not be the case for copy constructors:
#include <iostream>
class Base
{
public:
Base()
{
std::cout << "Base Constructor called" << std::endl;
}
Base(const Base& ref)
{
std::cout << "Base Copy Constructor called" << std::endl;
}
};
class Derived : Base
{
public:
Derived()
{
std::cout << "Derived Constructor called" << std::endl;
}
Derived(const Derived& ref) //: Base(ref) // <- without this Base copy constructor doesnt get called
{
std::cout << "Derived Copy Constructor called" << std::endl;
}
};
int main()
{
Derived d1;
Derived d2 = d1;
return 0;
}
Output without ": Base(ref)" :
Base Constructor called
Derived Constructor called
Base Constructor called
Derived Copy Constructor called
Output with ": Base(ref)" :
Base Constructor called
Derived Constructor called
Base Copy Constructor called
Derived Copy Constructor called
So unless you explicitly call the Base class copy constructor a new Base class object gets created instead of being copy constructed. So i guess only the Derived class members get actually copy constructed while all Base class members would be newly created by the Base class constructor. Now for me this seems like something you never really want. If you copy construct an object you expect all members to be copied instead of just a part of them.
Why are copy constructors different from normal constructors in this regard?

Why are copy constructors different from normal constructors in this regard?
They aren't. When you do not call a base class constructor, the default constructor is called for you. This happens for every contructor.

Related

Calling base's move constructor from derived copy constructor

I'm new to SO so let me know if I need to change anything. I did my best to be as thorough and provide example code. I know that many similar questions have been asked, I was unable to find one matching my specific problem though.
Furthermore, I'm aware that what I'm doing is not something one would do in 'real' code, I'm just trying to get a better understanding of r/l/p/x..values.
I have a base and a derived class, both having the default, copy, and move constructors. Now I want to have the copy constructor of the derived class calling the move constructor of the base class.
class Base
{
public:
Base(){ std::cout << "default base constructor called.\n"; }
Base(Base const &other) { std::cout << "copy base constructor called.\n"; }
Base(Base &&tmp) { std::cout << "move base constructor called.\n"; }
};
And basically the same for the derived class:
class Derived : public Base
{
public:
Derived(){ std::cout << "default derived constructor called.\n";}
Derived(Derived const &other)
:
Base(std::move(other)) // here I want to call Base(Base &&tmp)
{
std::cout << "copy derived constructor called.\n";
}
Derived(Derived &&tmp)
:
Base(std::move(tmp)) // correctly calls Base(Base &&tmp)!
{
std::cout << "move derived constructor called.\n";
}
};
So in my main function, I now want to call the copy constructor, which then calls the move constructor of the base class.
int main()
{
Derived der{};
Derived der_copy{ der };
Derived der_move{ std::move(der) };
}
The output I would get is this:
default base constructor called.
default derived constructor called.
copy base constructor called. <-- why not move?
copy derived constructor called.
move base constructor called.
move derived constructor called.
I was expecting the following:
default base constructor called.
default derived constructor called.
move base constructor called.
copy derived constructor called.
move base constructor called.
move derived constructor called.
So when I use std::move(tmp) in the derived move constructor (so on Base &&tmp) that the base move constructor is called, but when I use std::move(other) in the derived copy constructor (so on Base const &other) that the base copy constructor is called?
Tbh, this seems so strange that I'm afraid that I just made a mistake in my code, I checked everything multiple times but I can't seem to get the move base constructor called in the case above...
Thanks for your help!
In the copy constructor
Derived(const Derived& other)
std::move(other) will result in an xvalue expression of type const Derived&&.
This is a legal but somewhat weird type: std::move(other) is a temporary object, but you can't move from it, because it is constant. Such references have a limited number of use cases. See the declarations of std::as_const and std::ref for one particular example.
const Derived&& cannot bind to Base&&, that's why during the overload resolution between
Base(const Base&)
Base(Base&&)
the former is chosen by the compiler.
At the risk of getting undefined behaviour, you can cast constness away and write
Derived(const Derived& other) : Base(std::move(const_cast<Derived&>(other))) {}
to call the move constructor of Base. But don't do it in real code.
You need to change your Base class like this:
Base(const Base &&tmp) { std::cout << "move base constructor called.\n"; }

What's not inherited to a C++ Derived class? Apparently, operator= and some constructors are actually inherited

I am trying to learn about C++ inheritance, but one thing doesn't make any sense to me.
Everything a googled about what is not inherited by a derived class said that the constructors, friends, and operator= are not inherited. However, this information doesn't fit with the results of my program.
I did an example of inheritance and the result is what follows:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "constructor base class without parameters" << endl;
}
Base(int a)
{
cout << "constructor base class with int parameter" << endl;
}
Base(const Base& b)
{
cout << "copy constructor base class" << endl;
}
Base& operator= (const Base& base)
{
cout << "operator= base class" << endl;
}
};
class Derived: public Base
{
};
int main()
{
Derived d;
cout << endl << "here 1" << endl << endl;
Derived d2 = d;
cout << endl << "here 2" << endl << endl;
d = d2;
//Derived d3 (3); // ERROR!!
}
The output was:
constructor base class without parameters
here 1
copy constructor base class
here 2
operator= base class
If all the constructors and operator= are not inherited, why were operator=, default constructor and copy constructor of the base class called?
Dervied has no constructors, in this case a default constructor is generated which calls the default constructor of all base classes and members.
Similar things happen with the copy constructor and assignment operator. The Base class versions are being called by automatically generated Derived class versions.
This has nothing to do with inheritance of constructors or assignment operators.
Classes don't automatically inherit constructors, although you can force them to provide a base class's constructors with a using statement:
class Derived: public Base
{
public:
// Force this class to provide the base class's constructors
using Base::Base;
// Force this class to provide the base class's assignment operator
using Base::operator=;
};
The copy constructor wasn't inherited either. Instead, the compiler automatically generated a copy constructor for the derived class. If all of a class's member variables and base classes are copyable, then the class itself is copyable, and it'll generate the copy constructor automatically.
The same rules apply to the assignment operator: if all of a class's members provide a copy assignment operator, the compiler automatically generates one for the class itself.
Copy/move constructor is the exception according to the standard.
Referring to the standard:
For each non-template constructor in the candidate set of inherited
constructors other than a constructor having no parameters or a
copy/move constructor having a single parameter, a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class.
PS. Base& operator = (const Base& base)is not a constructor. It is assignment. So it works like any other member function. Since it is public in your example, it got inherited.

why constructors are called if they are not inherited?

the code is printing all the constructors. i read that constructors are not inherited when we derive a class from another class. then why creation of c is invoking constructors from b and a
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B, public A // Note the order
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
When the document you read said constructors are "not inherited", what it means is that if class A defines a constructor A::A(int x), then a child class B will not automatically have a constructor that takes an int.
However, it's still necessary to initialize the values of the parent class; otherwise, the parent object might be in an invalid state. Constructors are used to initialize classes, so means one of the parent class' constructors must be called from the child constructor's initializer list. If the parent class has a default constructor, that one gets called by default. That's what you see in your example. If the parent doesn't provide a default constructor, you have to specify which one you want called:
class A
{
public:
A(int x) { cout << "A's constructor called" << endl; }
};
class C: public A
{
public:
C()
: A(7) /* compilation will fail without this line */
{ cout << "C's constructor called" << endl; }
};
Constructors are not inherited in the traditional sense.
Classes are what's inherited.
But in order to construct a class, its constructor needs to be called. That's its job. Hard rule, no exceptions.
When you inherit one class from a second class, constructing the first class requires the second class to be constructed too. Because the first class always contains the second class. Another hard rule, no exceptions. That's what "inheritance" means.
So, constructing the first class will invoke its constructor. Then, to construct the second class its constructor will also need to be called (actually the second class gets constructed first, then the first class's construction takes place).
And that's why both constructors will be used.
i read that constructors are not inherited when we derive a class from another class
That is correct. However, you seem to have misunderstood the meaning of that.
Let's say you have:
struct A
{
A(int) {}
};
struct B : A
{
B() : A(0) {}
};
Given the above, you won't be able to use:
B b(10);
since A(int) is not inherited by B.
That's the crux of your misunderstanding.
then why creation of c is invoking constructors from b and a
However, when you construct a B, a constructor of B is called to initialize its members. A constructor of A must also be called so that the sub-object of B that corresponds to A can be initialized.
There are couple of ways to initialize the A-part of B.
You can use a constructor of A explicitly in the member initialization list by using the syntax:
B() : A(0) {}
Leave the member initialization empty, in which case the default constructor of A is called.
B() {}
That is equivalent to:
B() : A() {}
In the example I presented, that will result in a compiler error since the default constructor of A has been deleted by providing another constructor that is different than the default constructor.
Coming back to your implementation of the default constructor of C, you have:
C() { cout << "C's constructor called" << endl; }
That is equivalent to
C() : B(), A() { cout << "C's constructor called" << endl; }
B::B() and A::A() are called when an instance of C is constructed.
Constructors are called when classes are inherited. The inheritance basically gives the derived class instance anonymous member instances of the base classes, amongst other things. These instances need to be constructed so their constructors are called.
"Constructors are not inherited" means, that class C should and will have it's own constructors, despite fact that there were constructor of B, it will not be able to use constructor of B instead of constructor of C.
And that's exactly what you get: you get constructors of all parent classes.
When you have hierarchy of classes, and construct object from one, there will be sequential construction of all his parents, starting from the base one.
And when you will destroy them, there will be sequential destruction of him and all his parents, starting from him.
By rule: first created -- last destructed.
By not inherited, C++11 standard means this
class A
{
public:
A(int x) {}
};
class B: public A
{
};
int main(void)
{
B b(5);
return 0;
}
This will fail to compile because A(int) is not inherited. You can define B to explicitly inherit A(int) by
class B: public A
{
using A::A;
};
In your case you are defining all default ctors, and which explicitly defined or not, still exist, and will be called as part of the object initialization due to your C c declaration.
C++ inheritance basically creates a class made of parts of its super-classes. For example:
class A {
public:
A() {
std::cout << "Constructor A" << '\n';
}
};
class B : public A {
public:
B() {
std::cout << "Constructor B" << '\n';
}
};
class C : public B {
public:
C() {
std::cout << "Constructor C" << '\n';
}
};
Class C is actually class C, with a class B part, and a class A part. So in order to construct class C, we need to construct each of its parts by calling the constructors for those parts. The order of these constructors is from the most-base class to the most-derived class (in this case A to C). Most-base being the class at the top of the inheritance tree, and most-derived being the class at the bottom.
This same rule applies to destructors as well. The only difference is that the destrutors are called from most-derived to most-base (C to A).

Why the base class's constructor method is called twice?

Can anyone please tell me why the base class's constructor method is called twice?
#include <iostream>
using namespace std;
class A{
public:
A(){
cout << "default constructor of base class" << endl;
}
};
class B:public A{
public:
B(){
A();
cout << "default constructor of derived class" << endl;
}
};
int main(int argc, char **argv){
B b;
return 0;
}
And I'm getting this unexpected result:
default constructor of base class
default constructor of base class
default constructor of derived class
Once constructing the base sub-object of the B object in main:
B b;
Once constructing the temporary A object in the constructor of B:
A();
Perhaps you meant to initialise the A sub-object; do that in the initialiser list, not the constructor body:
B() : A() {
cout << "default constructor of derived class" << endl;
}
although, in this case, that would do exactly the same thing as leaving it out altogether.
The base-class constructor is called twice, because you create a temporary object of base-class in the derived-class ctor.
You might want to read about the ctor-init-list.
This would involve two calls to base's constructor.
1) In the derived initializer list.
2) Your explicit call.
That is every member is constructed in the initializer list. If you won't provide any specific constructor then default constructor is used.
It is because you are calling A() inside B directly. However, in inheritance, when the default constructor is not overridden, the constructor of the Base class is called at first.
So, just remove A() within B's constructor as class A is the Base, it's constructor will be called first.

how to force base class constructors to be called in derived classes?

basic c++ question i'm fairly sure. if i have a base class with a constructor that takes no parameters, and just initializes some of the protected members, does a derived class instantly call this base constructor too if it matches the parameters (wishful but unlikely thinking), and if not, is there a way to force it to automatically call said base constructor from the derived class WITHOUT having to explicitly tell it to do so in the derived class? I ask because i'm writing a wrapper of sorts and there are some protected members that i want initialized to specific values initially, and then i want to derive and manipulate this base class to my needs, but i wouldn't like an outside user to have to remember to explicitly call the base constructor or set these values within their own constructor.
Yes, the default base constructor is always called unless explicitly stated otherwise.
For example:
class A
{
public:
A() { std::cout << "A"; }
};
class B : A
{
public:
B() {}
};
int main()
{
B b;
return 0;
}
will output:
A
By "explicitly stated otherwise" I mean that you can call a different constructor from the derived class:
class A
{
public:
A() { std::cout << "A"; }
A(int) { std::cout << "AAA"; }
};
class B : A
{
public:
B() : A(1) {} //call A(int)
};
int main()
{
B b;
return 0;
}
will output
AAA
Important if you don't have a default constructor (you declare a non-default constructor and not a default one) or the default constructor is not visible (marked as private), you need to explicitly call an available constructor in the derived class.
If your base-class has a "default constructor" (a constructor that takes no parameters; either explicitly provided by you, or implicitly provided by the compiler because you didn't explicitly provide any constructors), then every derived-class constructor will automatically call that unless you specify that they call a different constructor instead.
(If your base-class doesn't have a "default constructor", because you've provided one or more constructors that take parameters and no constructor that doesn't, then it's a compile-error for a derived-class constructor not to indicate the base-class constructor it calls.)