用于存储类层次结构中的任何类的c ++类

时间:2016-07-29 11:26:39

标签: c++ c++11

让我假设我有类层次结构。 一个; B1,B2,B3-Bn全部来自A,而一些C类来自不同的B&。 我想要一个班级" UnifiedStorage"存储一个派生类,它不应该是模板化的,但它本身应该有std :: shared_ptr并且有两个函数:

template <typename T>
setData(std::shared_ptr<T> data/* A's derived class */)

template <typename T>
std::weak_ptr<T> getData()

我发现的唯一可能的实现是像Keeper一样创建smth:

class UnifiedStorage{
    class Keeper {
    public:
        virtual ~Keeper (){
        }
    };

    template <typename DataType>
    class SpecificKeeper : public Keeper {
    public:
        SpecificKeeper (std::shared_ptr<DataType> data): data(data) {}
        ~SpecificKeeper() = default;
        std::shared_ptr<DataType> data;
    };

    template <typename SpecificDataType>
    void setData (std::shared_ptr <SpecificDataType> d) {
        keeper.reset( new SpecificKeeper <SpecificDataType> (d) );
    }
    template <typename RequestedDataType>
    std::shared_ptr <RequestedDataType> getData () {
        SpecificKeeper <RequestedDataType>* specificKeeper =  dynamic_cast <SpecificKeeper <RequestedDataType> * > (keeper.data());
        if (specificKeeper == nullptr){
            return std::shared_ptr <RequestedDataType> ();
        }else{
            return specificKeeper->data;
        }
    }

    private:
        std::unique_ptr<Keeper> keeper;
}

但这种认识有很大的负面影响。我只能让shared_ptr输入我在setData中设置的类型。

例如,如果a已调用setData<B>(std::shared_ptr<B>)我无法getData<A>它返回null,但如果我将调用setData<A>(std::shared_ptr<B>) getData<A>将返回正确的指针。< / p>

1 个答案:

答案 0 :(得分:2)

你的问题归结为一个非常简单的事实。

在您的示例中B1派生自AB1A的子类。

但是,std::shared_ptr<B1>不是std::shared_ptr<A>的子类。 SpecificKeeper<B1>也不是SpecificKeeper<A>的子类。这不是C ++的工作原理。因此,你不能dynamic_cast从一个到另一个。

解决方案是完全摆脱模板,只需将std::shared_ptr<A>存储在守护者类中,然后在检索时执行std::dynamic_pointer_cast

一个简短的例子应该说清楚:

#include <memory>
#include <iostream>

class A { public: virtual ~A() {} };

class B : public A {};

class C : public A {};

int main()
{
    std::shared_ptr<B> b{new B};

    std::shared_ptr<A> a=b;

    std::shared_ptr<C> c=std::dynamic_pointer_cast<C>(a);

    std::cout << a.get() << std::endl; // Stored base pointer
    std::cout << c.get() << std::endl; // This will be nullptr, conversion failed
}

因此,您的UnifiedStorage只需要存储std::shared_ptr<A>。它不需要模板类。

GetData()将尝试std::dynamic_pointer_cast存储的指向所请求类型的指针。如果std::dynamic_pointer_cast成功,则您拥有共享指针。如果没有,则获得空std::shared_ptr