Aaron S
Aaron S

Reputation: 5323

boost::shared_ptr and Inheritance

I am facing a situation in which I have a std::vector of boost::shared_ptrs of a base class. During the course of my program I need to store shared pointers to derived class objects in that vector too and at some time later in the program, need to retrieve those shared pointers.

Following code illustrates my problem:

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

In the above code, if I change the code in BOOST_FOREACH from

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

to

Derived1Ptr d11 = dynamic_cast< Derived1Ptr >( bPtr );

, I get following compile time error on VS2010

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

My problem is that I want to work with boost::shared_ptr not references. Secondly, I am using dynamic_cast which will throw a std::bad_cast exception when object reference is of a different type (tried using it with shared pointers but get the compiler error mentioned previously). That is clearly very slow. I want to be able to use a more performance oriented approach. What I am looking for here is any solution instead of using dynamic_cast and exception handling.

Any suggestion with regards to code or change in design are welcome.

Upvotes: 10

Views: 9430

Answers (4)

Steve
Steve

Reputation: 1800

Your design seems to be missing the point; it would be better to use virtual functions to achive polymorphic behaviour.

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

Upvotes: 7

Nim
Nim

Reputation: 33655

You have several options:

Use inheritance (and polymorphism) properly! i.e. define pure virtual methods in your base class which you implement in your derived class (also, the extra shared_ptr type for each derived type is redundant!)

Use a variant type to hold all derived types (useful if you have a limited set). There is no need for dynamic cast then, you can specify a visitor to do what you need to.

Upvotes: 1

Bj&#246;rn Pollex
Bj&#246;rn Pollex

Reputation: 76778

If your vectors own the objects, you would be better off using a boost::ptr_vector.

Upvotes: 3

Henrik
Henrik

Reputation: 23324

Use dynamic_pointer_cast

Upvotes: 13

Related Questions