Почему это dynamic_cast из auto_ptr терпит неудачу?

    #include "iostream"

    class A {
        private:
        int a;
        public :

        A(): a(-1) {}
        int getA() {
            return a;
        }

    };

    class A;

    class B : public A {
        private:
        int b;
        public:

        B() : b(-1) {}

        int getB() {
            return b;
        }

    };

    int main() {
        std::auto_ptr<A> a = new A();

        std::auto_ptr<B> b = dynamic_cast<std::auto_ptr<B> > (a);

        return 0;

    }

ОШИБКА: невозможно dynamic_cast `(&a)->std::auto_ptr‹_Tp>::get() const


person kal    schedule 06.02.2009    source источник
comment
где объявление для a::get() ?   -  person cbrulak    schedule 06.02.2009


Ответы (5)


Ну, std::auto_ptr<B> не является производным от std::auto_ptr<A>. Но B происходит от A. auto_ptr об этом не знает (это не так умно). Похоже, вы хотите использовать общий указатель владения. boost::shared_ptr идеален, он также предоставляет dynamic_pointer_cast:

boost::shared_ptr<A> a = new A();
boost::shared_ptr<B> b = dynamic_pointer_cast<B> (a);

Для auto_ptr такая штука не может работать. Поскольку право собственности перейдет к b. Но если бросок терпит неудачу, b не может получить право собственности. Не понятно, что мне тогда делать. Вы, вероятно, должны были бы сказать, что если бросок потерпит неудачу, собственность сохранится - что звучит так, как будто это вызовет серьезные проблемы. Лучше всего начать с использования shared_ptr. И a, и b будут указывать на один и тот же объект, но B как shared_ptr<B>, а a как shared_ptr<A>.

person Johannes Schaub - litb    schedule 06.02.2009

динамическое литье так не работает. A : public B не означает auto_ptr<A> : public auto_ptr<B>. Вот почему shared_ptr в Boost обеспечивает shared_dynamic_cast. Однако вы можете написать динамическое приведение auto_ptr:

template<typename R, typename T>
std::auto_ptr<R> auto_ptr_dynamic_cast(std::auto_ptr<T>& in) {
  auto_ptr<R> rv;
  R* p;
  if( p = dynamic_cast<R*>( in.get() ) ) {
      in.release();
      rv = p;
  }
  return rv;

}

Просто знайте, что здесь происходит. Поскольку auto_ptrs имеют семантику владения, успешное приведение вниз означает, что оригинал имеет более общий тип, auto_ptr больше не владеет.

person Logan Capaldo    schedule 06.02.2009

Причина в том, что auto_ptr на самом деле не является указателем. Это интеллектуальный указатель, который является оболочкой указателя, но на самом деле не является указателем. Тип, который передается в качестве аргумента стиля шаблона в dynamic_cast, должен быть истинным типом указателя (или ссылки).

http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx

person JaredPar    schedule 06.02.2009

Вы пытаетесь преобразовать A* (возвращенное a.get()) в std::auto_ptr<B>, и, поскольку второй тип даже не является указателем, это не удается. Вероятно, вы просто хотите привести его к B*:

std::auto_ptr<A> a(new A());
std::auto_ptr<B> b(dynamic_cast<B*>(a.get()));

Это все равно не скомпилируется, потому что A и B не являются полиморфными типами. A должна иметь виртуальную функцию, чтобы сделать типы полиморфными. Это скомпилируется, но приведение просто выдаст std::bad_cast, поскольку на самом деле это не B*.

И даже если бы это был B*, при попытке использовать его произойдет ужасный сбой. Оба std::auto_ptrs a и b будут считать, что они владеют объектом и освобождают его позже, что приводит к всевозможным повреждениям памяти. Вероятно, вы захотите использовать a.release() после успешного приведения.

person sth    schedule 06.02.2009

Я думаю, что С++ хранит RTTI (информацию о типе времени выполнения) в vtable. Следовательно, чтобы использовать dynamic_cast‹> с объектом-экземпляром, объект должен иметь 'vtable'. C++ создает виртуальную таблицу только тогда, когда хотя бы одна функция объявлена ​​виртуальной в классе.

В классе A и классе B нет виртуальных функций. Это может быть причиной отказа dynamic_cast. Попробуйте объявить виртуальный деструктор в базовом классе.

person Nitin Bhide    schedule 06.02.2009