使用boost::shared_ptr在一个集合中创建不同的模板类

Different templated class in a set using boost::shared_ptr

本文关键字:创建 集合 一个 shared boost ptr 使用      更新时间:2023-10-16

我有一些设计上的问题,我想你们中有人可能有一些线索可以帮助我。

我试着用这个简单的例子来总结我的问题:

我有两个不同的类DerivedOneDerivedTwo,它们继承同一个Base类并共享一个方法的定义。
我有一组指向clientshared_ptr,其中有一个对象来自两个不同的类DerivedOneDerivedTwo
因为我不想使用Base*指针来保持这2个不同的类,我试图使客户端类模板。

但是我有两个不同的类,我不能把它们放在同一个集合里。
我认为shared_ptr可以在不指定模板参数的情况下保存对象指针,但是我错了,或者我不知道怎么做。

我看到的另一个解决方案是将这两个不同的client分开在两个不同的set

提前感谢您的建议。

代码如下:

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

如果你想看一下真实的代码:
https://github.com/gravitezero/Node/tree/experimental/src
Client对应connection
Base类是message
两个派生类是peplyrequest

boost共享模板指针不会执行任何没有常规指针(即将两种不同类型的指针放入同一个集合中)就无法执行的魔法。无论何时使用模板,都必须显式声明模板参数,因为模板所做的只是在编译时为您生成重复的代码。因此,当您使用模板时,编译器只是复制模板文件的次数与您使用模板参数声明的次数相同。没有模板参数,没有复制,没有模板。至少这是我的理解,我相信c++警察会纠正我,如果我错了。

因此,将两个不同类型放入同一个集合的方法是掩码放置在集合中的值。这样做的最基本的方法(也是糟糕的方法)是使您的void指针集合,然后根据上下文对插入和提取进行强制转换。这是很危险的,因为你将通过指针访问内存,而不检查指针是否指向正确的内存数量/格式(这是类型检查)。

所以真正的方法是按照pmr的建议。将集合设置为基类型指针的集合,并在从列表插入和提取时使用动态强制转换在类型之间强制转换。动态强制转换将在运行时进行检查,以确保强制转换的来源和目标类型是兼容的。如果你从Derived1转换到Base,然后再从Base转换到Derived1,这是可以的。如果您在指向相同内存的指针上从Derived1强制转换为base,然后再从base强制转换为Derived2,这将在运行时失败,因为Derived2和Derived1不兼容。

这个解释有点长,因为几个月前我也遇到了同样的设计问题,直到我看了一些资料。

为什么不使用指向Base实例的指针呢?如果使用运行时多态性,这是唯一的方法。如果实际上不需要运行时多态性,那么使用虚成员函数是错误的。

只要使用boost::scoped_ptr或(更好)c++ 11 std::unique_ptr来保持base*Client

如果您选择放弃运行时多态性,您应该研究CRTP来实现静态多态性。