c++ inheritance question
-
29-10-2019 - |
Question
I have a question about this:
class A
{
int a;
int* pa;
public:
A(int i):a(i) , pa(new int(a))
{
cout<<"A ctor"<<a<<endl;
}
~A()
{
delete pa;
cout<<"dtor\n";
}
int * &get()
{
return pa;
}
};
class B : public A
{
int b;
public:
B (A obj): A(obj) , b(0)
{
cout<<"B ctor\n";
}
~B()
{
cout<<"B dtor\n";
}
};
int main()
{
int i = 23 ;
A* p = new B(i);
}
Can tell me why the last line in main
compiles? I pass an int
into B
's constructor which expects an A
object instead. I believe that the int
is translated to an A
in B
's constructor, but why?
Thanks in advance.
Avri.
Solution
Since you have not declared A
constructor as explicit
compiler is creating an anomymous instance of A
using i
and using it to initialize B
instance. If you don't want the compiler to do these implicit conversions declare your costructor as explicit
. Then you will get a compiler error.
OTHER TIPS
Because A
has a single parameter constructor which takes an int
and isn't marked explicit
you can implicitly convert an int
to an A
.
When you do new B(i)
, because the only viable constructor for B
takes an A
, an attempt is made to convert i
to an A
and construct the new B
from that. This conversion is done by creating a temporary A
using the constructor that takes an int
.
When the B
object is constructed, the base class A
is copy constructed from the temporary A
which means copying the member variables a
and pa
from the temporary A
.
Strictly, because the constructor takes an A
object by value, the temporary is, conceptually, copied again. The compiler may, however, eliminate the temporary by constructing the constructor parameter for B
directly from i
so the effect may well look like just a single copy.
This will cause a serious error because when the temporary A
is destroyed, delete pa
will cause the dynamically allocated int
to be destroyed but the base class A of the newly allocated B
object will still have a copy of this pointer which now no longer points at an invalid object. If the compiler doesn't eliminate one of the copies, a "double free" will happen immediately.
The key aspect of A
is that it has a user-defined destructor that performs a resource action (deallocation). This is a strong warning that A
needs a user-defined copy constructor and copy assignment operator because compiler generated version are likely not to work consistently with the design of A
.
This is known as the "rule of three" which says that if you need a user-defined version of one of the destructor, copy constructor or copy assignment operator then you are likely to need user-defined versions of all of them.
Were you to attempt to free the dynamically allocated B
object in your example, it would likely cause a "double free" error. In addition, A
's destructor would need to be marked as virtual
for a delete through a pointer to A
to work correctly.
Since there is a conversion from int
to A
, implicitly your code is translated into
A* p = new B(A(i));