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

Posted

技术标签:

【中文标题】用于存储类层次结构中的任何类的 c++ 类【英文标题】:c++ class for storing any class from class hierarchy 【发布时间】: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。 【参考方案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> bnew 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*)这样的解决方案,我该如何解决这个问题

以上是关于用于存储类层次结构中的任何类的 c++ 类的主要内容,如果未能解决你的问题,请参考以下文章

C++ 几何层次结构、类向上转换和继承

列出给定类的层次结构中的所有基类?

在层次结构中创建类的指针数组

java 在Java中打印任何给定类的类层次结构

C++ 虚继承的对象模型

由于开闭原则处理继承层次结构