Consider this piece of code:
#include <vector>
#include <iostream>
using namespace std;
class Base
{
char _type;
public:
Base(char type):
_type(type)
{}
~Base() {
cout << "Base destructor: " << _type << endl;
}
};
class uncopyable
{
protected:
uncopyable() {}
~uncopyable() {}
private:
uncopyable( const uncopyable& );
const uncopyable& operator=( const uncopyable& );
};
class Child : public Base, private uncopyable
{
int j;
public:
Child():
Base('c')
{}
~Child() {
cout << "Child destructor" << endl;
}
};
int main()
{
vector<Base> v;
Base b('b');
Child c;
v.push_back(b);
v.push_back(c);
return 0;
}
The output on my system is:
Base destructor: b
Child destructor
Base destructor: c
Base destructor: b
Base destructor: b
Base destructor: c
My questions are:
Why is the destructor of Base
(with type b) called three times instead of two (do we have more than two copies of object b)?
What happens when we copy an object of type Child
, considering the copy-constructor of one of its parents is private. Is it undefined behavior?
I was expecting to get a compile-time error whenever I try to copy an object of type Child
. I thought the child's default copy-constructor would try to call the private copy-constructor of the Uncopyable class and cause compilation error. Why doesn't it give compile errors?
The reason the code is designed this way is because the Child
class is huge.
The desired behavior is throwing away the child data whenever a client tries to copy a Child
object (calling the destructor of Child
without calling the destructor of Base
).
This piece of code achieves that, but I guess it results in undefined behavior and has memory leak (never calls the destructor of Child
for the copied instance).
Copy constructor is not inherited.
For multiple inheritance order of constructor call is, the base class's constructors are called in the order of inheritance and then the derived class's constructor.
A class can have multiple copy constructors, e.g. both T::T(const T&) and T::T(T&). If some user-defined copy constructors are present, the user may still force the generation of the implicitly declared copy constructor with the keyword default .
Constructor in Multiple Inheritance in C++Constructor is automatically called when the object is created. Multiple Inheritance: Multiple Inheritance is a feature of C++ where a class can derive from several(two or more) base classes.
Any other constructor is not a copy constructor. The copy constructor may be used as a normal ctor, but is used implicitly by the language for copy assignment Coffe c = other_coffee, which is then equivalent to Coffee c(other_coffee), and when passing the object by value to a function, e.g. drink(Coffee)requires a copy.
The constructors of inherited classes are called in the same order in which they are inherited. …. Example 1: Below is the C++ program to show the concept of Constructor in Multiple Inheritance.
You cannot copy construct a subclass (Coffee) from any and all arbitrary objects that sub-classes from super class Drink. So, the answer has to be that you must limit the copy constructor accept the same class (Coffee) for the copy constructor.
Copy constructor is called when a new object is created from an existing object, as a copy of the existing object. Assignment operator is called when an already initialized object is assigned a new value from another existing object. In the above example (1) calls copy constructor and (2) calls assignment operator. See this for more details.
Here is what happens in your code:
int main()
{
vector<Base> v; // 1
Base b('b'); // 2
Child c; // 3
v.push_back(b); // 4
v.push_back(c); // 5
return 0;
} // 6
line 1: vector v constructed
line 2: Base b constructed (calling Base's constructor)
line 3: Child c constructed (calling Child's constructor and Base's constructor)
line 4: v is current at maximum capacity and needs to be resized.
Memory is allocated for 1 element of Base by v.
Base b copied into v[0] (calling Base's copy constructor).
line 5: v is again at maximum capacity and needs to be resized.
Memory is allocated for 2 elements of Base by v.
The old v[0] is copied into the new v[0] (calling Base's copy constructor).
The old v[0] is deleted (calling Base's destructor ("Base destructor: b")).
Child c is copied into v[1] (calling Base's copy constructor).
line 6: c, b, and v run out of scope.
Child c is deleted (calling Child's destructor ("Child destructor") then Base's destructor ("Base destructor: c").
Base b is deleted (calling Base's destructor ("Base destructor: b")).
Base v[0], v[1] are deleted (calling Base's destructor twice ("Base destructor: b", "Base destructor: c")).
There is no memory leak - for every constructor in the above sequence a corresponding destructor is called.
Additionally, you seem to be very confused about copy constructors. Child c gets passed to push_back as a Base& - which then calls Base's copy constructor as expected. Since Base's implicit copy constructor is not virtual or overriden, having Child derive from uncopyable does nothing to change this.
Note that a vector<Base>
cannot ever store an object of type Child; it only knows to allocate enough memory for a Base. What occurs when assigning an instance of Child to a Base is known as slicing, which, while often unintended and misunderstood, seems like it may actually be what you want in your described scenario.
I was expecting to get a compile-time error whenever I try to copy an object of type Child.
You aren't copying a Child
object. When you put Child
c
into a vector<Base>
, only the Base
gets copied. It's basically the same as executing b = c;
. If you do copy/assign Child
you will get an error.
Child d = c; // compile error
The default copy constructor will call the copy constructors of any base class and member objects and do a bitwise copy for primitives and pointers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With