从基类转换为未知的派生类

时间:2011-12-16 23:58:26

标签: c++ templates casting

给定一个对象初始化如下:

Base* a = new Derived();
Container<Base> c(a);

,其中

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.
    }
};

显然,这与实际代码相比非常简单,但问题是如何将object从其模板化类型转换为实际的派生类型(如果它们不同),这是不知道的?

我无法修改BaseDerived,甚至任何调用Container的代码,只能修改Container类本身。

5 个答案:

答案 0 :(得分:4)

您需要模板化构造函数并存储类型删除的删除器。 shared_ptr就是这样做的。

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);
    }
};

答案 1 :(得分:2)

如果您能够更改创建代码,则可以使用此方法:

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); }
};

在调用代码中:

Base* a = new Derived();
Container<Base> c(a, &deleter<Derived>);

答案 2 :(得分:0)

提示(因为这是作业):查找关键字virtual

答案 3 :(得分:0)

如果您无法同时更改 Base Derived 或将析构函数设为虚拟,则可以将deleteObject设为模板函数

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;
}

答案 4 :(得分:0)

编辑:我没有意识到你也无法修改Container签名......

如果您可以修改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>();
编辑:有人早些时候发布了相同的解决方案。