Home > Software engineering >  How to deal with a covariance of base pointers, casting from derived to base class for using methods
How to deal with a covariance of base pointers, casting from derived to base class for using methods

Time:02-03

I have the following classes:

class base{};
class derived1:public base{};
class derived2:public base{};

I also have an implemented container pool to which I have no editing access. In each of the 3 .h files, I define the following pool respectively:

typedef pool<base> basesPool;
typedef pool<base> derived1Pool;
typedef pool<base> derived2Pool;

At some point in the flow, I am getting an object out of the pool, and assigning it to a general pointer of type base with respect to a flag:

derived1Pool d1pool;
derived1Pool d2pool;
base* element;

if(flag){
  d1pool = new derived1Pool();
  element = d1pool ->alloc(); 
}
else{
  d2pool = new derived2Pool();
  element = d2pool ->alloc(); 
}

Later on, I am trying to clean using the following code:

if(flag){
  d1pool->free(element); 
}
else{
  d2pool->free(element); 
}

I am getting an error due to a covariance problem:

error: no matching function for call to 'pool<derived1Pool>::free(base*&)'

An easy solution would be to define two pointers. I am trying to avoid this. Is there an elegant option to convert from the base pointer to the derived pointer? I have seen this post and tried all variations of dynamic_casting I could think of to no avail.

CodePudding user response:

The issue you have is that you cannot cast (dynamically or otherwise) a non-lvalue base class pointer to a non-const reference to a pointer to a derived class, which is what is required as the argument to your free calls.

As you have stated that you cannot change the pool class definition (or its free member function's argument type), you could get round this by creating local (to the if and else blocks) pointers of the correct type, initialize them by dynamically casting the element pointer, and use those as the arguments to the free calls:

if(flag){
    derived1* d1p = dynamic_cast<derived1*>(element);
    d1pool->free(d1p);
    element = d1p; // See note below 
}
else{
    derived2* d2p = dynamic_cast<derived2*>(element);
    d2pool->free(d2p); 
    element = d2p; // See note below
}

Note: The reason why I have included the assignments back to element after each call is that it is likely that the free function modifies its given pointer (probably setting it to nullptr, but I can't be sure). So, we need to manually propagate that change, because we have passed local/temporary pointers and the free function's changes will only apply to those.

  • Related