boost :: shared_ptr и Наследование - PullRequest
10 голосов
/ 03 марта 2011

Я сталкиваюсь с ситуацией, в которой у меня есть std::vector из boost::shared_ptr базового класса.В течение моей программы мне нужно хранить общие указатели для объектов производных классов и в этом векторе, а через некоторое время в программе нужно извлечь эти общие указатели.

Следующий код иллюстрирует мою проблему:

#include <iostream>
#include <vector>
using namespace std;

#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>

class Base
{
public:
    virtual ~Base()
    {
    }
};
/******************************************/

typedef boost::shared_ptr< Base > BasePtr;
/******************************************/

class Derived1 : public Base
{
public:
    void derived1_test()
    {
        cout << "derived1_test" << endl;
    }
    /******************************************/
    int i1;
};
/******************************************/

typedef boost::shared_ptr< Derived1 > Derived1Ptr;
/******************************************/

class Derived2 : public Base
{
public:
    void derived2_test()
    {
        cout << "derived2_test" << endl;
    }
    /******************************************/
    int i2;
};
/******************************************/

typedef boost::shared_ptr< Derived2 > Derived2Ptr;
/******************************************/

int main()
{
    Derived1Ptr d1 = boost::make_shared< Derived1 >();
    Derived2Ptr d2 = boost::make_shared< Derived2 >();

    vector< BasePtr > v;
    v.push_back( d1 );
    v.push_back( d2 );
    BOOST_FOREACH(BasePtr bPtr, v)
    {
        try
        {
            Derived1& d11 = dynamic_cast< Derived1& >( *bPtr );
            d11.derived1_test();
        }
        catch (const std::bad_cast& e)
        {
            Derived2& d22 = dynamic_cast< Derived2& >( *bPtr );
            d22.derived2_test();
        }
    }
    return 0;
}

В приведенном выше коде, если я изменю код в BOOST_FOREACH с

Derived1& d11 = dynamic_cast< Derived1& >( *bPtr );

на

Derived1Ptr d11 = dynamic_cast< Derived1Ptr >( bPtr );

, я получаю следующую ошибку времени компиляции на VS2010

invalid target type for dynamic_cast target type must be a pointer or reference to a defined class

Моя проблема в том, что я хочу работать с boost::shared_ptr, а не ссылками.Во-вторых, я использую dynamic_cast, который вызывает исключение std::bad_cast, когда ссылка на объект другого типа (пробовал использовать его с общими указателями, но получал ошибку компилятора, упомянутую ранее).Это явно очень медленно.Я хочу использовать более ориентированный на производительность подход.То, что я ищу здесь, это любое решение вместо использования dynamic_cast и обработки исключений.

Любые предложения относительно кода или изменения дизайна приветствуются.

Ответы [ 4 ]

13 голосов
/ 03 марта 2011

Использование dynamic_pointer_cast

7 голосов
/ 03 марта 2011

Ваш дизайн, кажется, не хватает смысла; было бы лучше использовать virtual функции для достижения полиморфного поведения.

#include <iostream>
#include <vector>
using namespace std;

#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>

class Base
{
public:
    virtual ~Base() {}
    virtual void test() = 0;
};
/******************************************/

typedef boost::shared_ptr< Base > BasePtr;
/******************************************/

class Derived1 : public Base
{
public:
    void test()
    {
        cout << "derived1_test" << endl;
    }
    /******************************************/
    int i1;
};

class Derived2 : public Base
{
public:
    void test()
    {
        cout << "derived2_test" << endl;
    }
    /******************************************/
    int i2;
};

int main()
{
    BasePtr d1 = boost::make_shared< Derived1 >();
    BasePtr d2 = boost::make_shared< Derived2 >();

    vector< BasePtr > v;
    v.push_back( d1 );
    v.push_back( d2 );
    BOOST_FOREACH(BasePtr &bPtr, v) // I use a reference here for efficiency.
    {
        bPtr->test();
    }
    return 0;
}
3 голосов
/ 03 марта 2011

Если ваши векторы принадлежат объектам, вам лучше использовать boost::ptr_vector.

1 голос
/ 03 марта 2011

У вас есть несколько вариантов:

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

Используйте тип варианта для хранения всех производных типов (полезно, если у вас ограниченный набор). Тогда нет необходимости в динамическом приведении, вы можете указать посетителю делать то, что вам нужно.

...