C++: не является полиморфным типом при использовании boost::dynamic_pointer_cast

Почему я получаю следующую ошибку для следующего кода?

1>C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(259): error C2683: 'dynamic_cast' : 'my_namespace::A' is not a polymorphic type
1>          D:\[location]\[header_filename].h(35) : see declaration of 'my_namespace::A'
1>          C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(522) : see reference to function template instantiation 'boost::shared_ptr<T>::shared_ptr<my_namespace::A>(const boost::shared_ptr<my_namespace::A> &,boost::detail::dynamic_cast_tag)' being compiled
1>          with
1>          [
1>              T=my_namespace::B
1>          ]
1>          [location]\[source_filename].cpp(217) : see reference to function template instantiation 'boost::shared_ptr<T> boost::dynamic_pointer_cast<my_namespace::B,striker::A>(const boost::shared_ptr<my_namespace::A> &)' being compiled
1>          with
1>          [
1>              T=my_namespace::B
1>          ]
1>C:\Libs\boost_1_44\boost/smart_ptr/shared_ptr.hpp(260): fatal error C1903: unable to recover from previous error(s); stopping compilation

Код С++ примерно такой:

#include <list>
#include "boost/pointer_cast.hpp"
#include "boost/shared_ptr.hpp"

struct A
{
public:
    A(const MyEnum an_enum_, const int an_int_) :
        an_enum(an_enum_),
        an_int(an_int_)
    {}

    const MyEnum an_enum;
    const int an_int;
};

struct B : public A {
public:
    B(const int some_int_, const MyStruct &a_struct_) :
        A(ENUM_OPTION_A, an_int_),
        a_struct(a_struct_)
    {}

    const MyStruct a_struct;
};


// Ussage in some function:
// ...
boost::shared_ptr<A> a_ptr = boost::shared_ptr<A>( new B() );
std::list<boost::shared_ptr<A>> a_list;
a_list.push_back(a_ptr);
// ...
boost::shared_ptr<A> a_ptr2 = a_list.front();
boost::shared_ptr<B> b_ptr = boost::dynamic_pointer_cast<B>(a_ptr2); // <-- error here
// ...

person Jonathan    schedule 29.04.2011    source источник


Ответы (3)


dynamic_cast работает ТОЛЬКО с полиморфным классом. А класс polymorphic — это тот, в котором есть хотя бы одна функция virtual, пусть даже деструктор.

//polymorphic classes
struct A
{
   virtual ~A(); //even virtual destructor makes a class polymorphic!
};
struct B : A
{
   void f();
};

//non-polymorphic classes    
struct C
{
   ~C(); //not virtual
};

struct D : C
{
   void f(); //not virtual either
};

В приведенном выше коде A и B являются полиморфными классами, а C и D — нет.

A *pA = new B();
B *pB = dynamic_cast<B*>(pA); //okay

C *pC = new D();
D *pD = dynamic_cast<D*>(pC);  //error -  not polymorphic class

Обратите внимание, что в dynamic_cast только исходный тип должен быть полиморфным для компиляции. Если назначение не является полиморфным, то dynamic_cast вернет нулевой указатель.

D *pD = dynamic_cast<D*>(pA);  //okay - source (pA) is polymorphic

if ( pD )  
      cout << "pD is not null" ;
else 
      cout << "pD is null";

Вывод:

pD is null

Онлайн-демонстрация: https://web.archive.org/web/20000000000000/http://www.ideone.com/Yesxc

person Nawaz    schedule 29.04.2011
comment
+1 однако, почему вы прокомментировали для D::f(); будет ли это делать полиморфное отношение, даже если оно было виртуальным? - person iammilind; 29.04.2011
comment
@iammilind: Если D::f() является виртуальным, то D будет полиморфным классом, хотя C по-прежнему будет неполиморфным. - person Nawaz; 29.04.2011
comment
истинный. но нас будет интересовать dynamic_cast между C и D. Так что не имеет значения, является ли D полиморфным или нет. - person iammilind; 29.04.2011
comment
@iammilind: если D не является полиморфным, то dynamic_cast<D*>(pC) вернет NULL, если pC является полиморфным или если pC НЕ полиморфным, код не будет компилироваться. - person Nawaz; 29.04.2011

'dynamic_cast' : 'my_namespace::A' is not a polymorphic type, потому что он не определяет и не наследует ни одной функции virtual. Просто добавьте виртуальный деструктор, и все будет в порядке.

dynamic_cast работает только для таких "полиморфных" типов.

person Alexander Gessler    schedule 29.04.2011

struct A не имеет виртуальных методов (даже деструктора), поэтому вы не можете dynamic_cast из A*dynamic_cast можно использовать только указатели на типы с хотя бы одной виртуальной функцией-членом. boost::dynamic_pointer_cast делает dynamic_cast внутри, к нему предъявляются те же требования.

person sharptooth    schedule 29.04.2011