【问题标题】:c++ class for storing any class from class hierarchy用于存储类层次结构中的任何类的 c++ 类
【发布时间】:2016-07-29 11:26:38
【问题描述】:

假设我有类层次结构。 一种; B1、B2、B3-Bn 都派生自 A,还有一些 C 类派生自不同的 B。 我想要一个类“UnifiedStorage”来存储A派生类,它不应该被模板化,但它本身应该有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 中设置的类型。

例如,如果我调用了 setData&lt;B&gt;(std::shared_ptr&lt;B&gt;) 我不能 getData&lt;A&gt; 它返回 null,但如果我调用 setData&lt;A&gt;(std::shared_ptr&lt;B&gt;) getData&lt;A&gt; 将返回正确的指针。

【问题讨论】:

  • 你不能用:void setData(std::shared_ptr&lt;A&gt; ptr) { m_data = ptr; } template &lt;typename T&gt; std::weak_ptr&lt;T&gt; getData() { return std::static_pointer_cast&lt;T&gt;(m_data); },成为会员std::shared_ptr&lt;A&gt; m_data;吗?
  • 我有一个邪恶的:拥有std::function&lt;void()&gt;并存储{ throw *this }。不用于实际代码,仅用于完整性和下一个 IOCCC。

标签: c++ c++11


【解决方案1】:

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

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

但是,std::shared_ptr&lt;B1&gt; 不是std::shared_ptr&lt;A&gt; 的子类。 SpecificKeeper&lt;B1&gt; 也不是 SpecificKeeper&lt;A&gt; 的子类。这不是 C++ 的工作方式。因此你不能dynamic_cast从一个到另一个。

解决方案是完全摆脱模板,只需将std::shared_ptr&lt;A&gt; 存储在keeper 类中,然后在检索时执行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&lt;A&gt;。它不需要模板类。

GetData() 将尝试将std::dynamic_pointer_cast 存储的指针指向请求的类型。如果std::dynamic_pointer_cast 成功,您就有了共享指针。如果没有,你会得到一个空的std::shared_ptr

【讨论】:

  • 对不起,也许你也可以帮助我。如果我不仅要存储 A 派生类怎么办?如果没有像“任何类型”实现(通常基于 void*)这样的解决方案,我该如何解决这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
相关资源
最近更新 更多