开发者

Different templated class in a set using boost::shared_ptr

I have some design problems, I thought one of you might have some clue to help me.

I tried to summarize my problem to this simple example :

I have two different class DerivedOne and DerivedTwo which inherit from the same Base class and share the definition of a method.

I have a set of shared_ptr pointing to client, which have one object from two different class DerivedOne and DerivedTwo.

Because I don't want to use a Base* pointer to hold this 2 different class, I tried to make the client class template.

But I have 2 different class, and I can't hold them in the same set.

I thought shared_ptr could hold an object pointer without specifying the template argument, but I was wrong, or I don't know how to do.

The other solution I see, is to separate those 2 different client in 2 different set

Thanks in advance for any suggestions.

Here is the code :

#include <iostream>
#include <set>
#include <boost/shared_ptr.hpp>

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

class Derived_one
    : public Base
{
    public:
        void test() {
            std::cout << "Derived One" << std::endl;
        }            
};

class Derived_two
    : public Base
{
    public:
        void test() {
            std::cout << "Derived Two" << std::endl;
        }
};

template <class temp_arg>
class Client
{
    public:        
        int test(){
            obj_.test();
        }

    protected:
        temp_arg obj_;

};

typedef Client<Derived_one> ClientOne;
typedef Client<Derived_two> ClientTwo;    

/// Here I don't want to specify any of the two previously declared client :
//typedef boost::shared_ptr<Client> Client_ptr;
typedef boost::shared_ptr<ClientOne> Client_ptr;

int main(int, const char**)
{
    std::set<Client_ptr> Clients_;
    Client_ptr client_(new ClientOne());

    Clients_.insert(client_);
    client_->test();

    return 0;
}

If you want to give a look to the real code :

https://github.com/gravitezero/Node/开发者_如何学JAVAtree/experimental/src

Client correspond to connection

The Base class is message

The two derived class are peply and request.


The boost shared template pointers wont perform any magic that you can't do without regular pointers (namely putting two different types into the same collection). Whenever using a template you must explicitly declare the template arguments, because alls a template does is generate duplicate code for you at compile time. So when you use a template, the compiler simply duplicates the template file as many times as you have declared it with the template arguments. No template arguments, no duplication, no template. At least this is my understanding, I'm sure the C++ Police will correct me if I'm wrong.

So the way to put two different types into the same collection is to mask the value being placed in the collection. The most basic way of doing this (and bad way) is to make your collection of void pointers and then cast on insert and extraction depending on the context. This is dangerous, because then you will be accessing memory through the pointer without checking that the pointer points to the correct amount/format of memory (this is type checking).

So the real way to do this is as pmr suggested. Make your collection a collection of base type pointers and use dynamic cast to cast between the types when inserting and extracting from the list. A dynamic cast will check at run-time to make sure that the type you are casting from and to are compatible. IE if you cast from Derived1 to Base, and then later from Base to Derived1 this is okay. If you cast from Derived1 to base, and then later from base to Derived2 on a pointer pointing to the same memory, this will fail at run-time, because Derived2 and Derived1 are not compatible.

This explanation is a little long, because I had the same design trouble a few months ago, until I did some reading.


Why don't you want to use a pointer to a Base instance? If you use runtime-polymorphism this is the only way. If you actually don't need the runtime-polymorphism, virtual member functions are the wrong way to go.

Just use a boost::scoped_ptr or (better) a C++11 std::unique_ptr to keep a base* in Client.

If you choose to abandon the runtime-polymorphism you should look into CRTP to implement static polymorphism.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜