Reputation: 96904
Given an object initialized like so:
Base* a = new Derived();
Container<Base> c(a);
where
class Base {
...
protected:
~Base();
}
class Derived : public Base {...};
template <typename T>
class Container {
private:
T* object;
public:
Container(T* o) : object(o) {}
void deleteObject() {
delete object; // Object must be casted to (unknown) derived type to call destructor.
}
};
Obviously this is very simplified from the actual code, but the question is how do I cast object
from its templated type to its actual, derived type (if they are different), which is not known?
I cannot modify Base
or Derived
, or even any of the code calling Container
, only the Container
class itself.
Upvotes: 1
Views: 1921
Reputation: 146910
You need to template the constructor and store a type-erased deleter. This is how shared_ptr
does it.
template <typename T>
class Container {
private:
T* object;
std::function<void(T*)> deleter;
public:
template<typename U> Container(U* o) : object(o) {
deleter = [](T* ptr) { delete static_cast<U*>(ptr); };
}
void deleteObject() {
deleter(object);
}
};
Upvotes: 4
Reputation: 3918
EDIT: I didn't realize you cannot modify Container
signature as well...
If you can modify your deleteObject
:
template <typename T>
class Container {
private:
T* object;
public:
Container(T* o) : object(o) {}
template< typename PDerived >
void deleteObject() {
delete static_cast< PDerived* >( object );
}
};
Base* a = new Derived();
Container<Base> c(a);
c.deleteObject<Derived>();
EDIT: Someone posted same solution earlier.
Upvotes: 0
Reputation: 24403
If you cannot change both the Base or Derived or make the destructor virtual, you can make the deleteObject a template function
template <typename T>
class Container {
private:
T* object;
public:
Container(T* o) : object(o) {}
template <typename U>
void deleteObject() {
U* c = static_cast<U*>(object);
delete c;
}
};
int main(void)
{
Base* a = new Derived();
Container<Base> *b = new Container<Base>(a);
b->deleteObject<Derived>();
return 0;
}
Upvotes: 0
Reputation: 131779
If you're able to change the creation code, you might get away with this:
template<class T>
void deleter(void* p){
delete static_cast<T*>(p);
}
template<class T>
class Container{
private:
T* obj;
typedef void (*deleter_func)(void*);
deleter_func obj_deleter;
public:
Container(T* o, deleter_func df)
: obj(o), obj_deleter(df) {}
void deleteObject(){ obj_deleter(obj); }
};
And in the calling code:
Base* a = new Derived();
Container<Base> c(a, &deleter<Derived>);
Upvotes: 2