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.

Was it helpful?

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));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top