Приведение из базового класса в неизвестный производный класс - PullRequest
1 голос
/ 17 декабря 2011

Учитывая объект, инициализированный так:

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 из его шаблонного типа в его фактический, производный тип (если они отличаются), который не известен?

Я не могу изменить Base или Derived, или даже любой код, вызывающий Container, только сам класс Container.

Ответы [ 5 ]

4 голосов
/ 17 декабря 2011

Вам необходимо создать шаблон конструктора и сохранить удаленный тип.Вот как 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);
    }
};
2 голосов
/ 17 декабря 2011

Если вам удастся изменить код создания, вам может это сойтись:

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>);
0 голосов
/ 17 декабря 2011

РЕДАКТИРОВАТЬ: Я не знал, что вы не можете изменить 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>();

РЕДАКТИРОВАТЬ: Кто-то опубликовал такое же решение ранее.

0 голосов
/ 17 декабря 2011

Если вы не можете изменить оба значения 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;
}
0 голосов
/ 17 декабря 2011

Подсказка (поскольку это домашняя работа): найдите ключевое слово virtual.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...