如何在 C++ 中转换我的自定义共享指针

问题描述 投票:0回答:1

我正在用 C++ 创建一个自定义共享指针来了解这些东西是如何工作的。

我的实现不是通用目的,我只想将它与类 Foo 或其任何子类一起使用。

这就是我的课程的样子:

template <typename T, typename = std::enable_if<std::is_same_v<T, Foo> || std::is_base_of_v<Foo, T>>>
class ReferenceCounter final
{
private:
    T* m_Value;
    unsigned int m_Counter;
};


template <typename T, typename = std::enable_if<std::is_same_v<T, Foo> || std::is_base_of_v<Foo, T>>>
class SharedPtr final
{
private:
    ReferenceCounter<T>* m_ReferenceCounter;
};

我还实现了所有构造函数、复制构造函数、赋值运算符等。我没有在这里展示它们,因为代码很多,而且我认为它与问题无关。

现在我想添加两个功能:

  • 我希望能够将共享指针从子类隐式转换为基类,如下所示:
    SharedPtr<Foo> f = MakeShared<FooDerived>();
  • 我希望能够从基类转换为派生类,如果无法转换则返回 nullptr:
    SharedPtr<Foo> f = ...; SharedPtr<FooDerived> fd = TryCast<FooDerived>(f);

如何实施?

编辑1:较小的文本和标题更改

编辑2:添加模板限制

c++ shared-ptr smart-pointers
1个回答
0
投票

我会采取这种方法:

#include <memory>
#include <type_traits>
#include <iostream>

//--------------------------------------------------------------------------------
// Foo and Bar structs 

struct Foo
{
    virtual ~Foo() = default;
    virtual void DoSomething() const
    {
        std::cout << "Foo\n";
    }
};

struct Derived : 
    public Foo
{
    void DoSomething() const override
    {
        std::cout << "Derived\n";
    }
};

struct Bar
{
};

//--------------------------------------------------------------------------------
// your own special shared pointer type
// Note, no inheritance here. But still reuse of std::shared_ptr

class shared_foo_ptr_t final
{
public:
    // make sure all the move and copy constructors are defined
    // since there is a custom (private) constructor
    ~shared_foo_ptr_t() = default;
    shared_foo_ptr_t(const shared_foo_ptr_t&) = default;
    shared_foo_ptr_t& operator=(shared_foo_ptr_t& ) = default;
    shared_foo_ptr_t(shared_foo_ptr_t&&) = default;
    shared_foo_ptr_t& operator=(shared_foo_ptr_t&&) = default;

    // here is your template function
    // with extra checks on Foo being a base
    template<typename type_t>
    static auto create() -> std::enable_if_t<std::is_base_of_v<Foo,type_t>, shared_foo_ptr_t>
    {
        shared_foo_ptr_t shared_foo_ptr{ std::make_shared<type_t>() };
        return shared_foo_ptr;
    }

    // explicit! casting operator
    explicit operator std::shared_ptr<Foo>() const noexcept
    {
        return m_foo_ptr;
    }

    auto& operator->()
    {
        return m_foo_ptr;
    }

    const auto& operator->() const
    {
        return m_foo_ptr;
    }

    auto* get() 
    {
        return m_foo_ptr.get();
    }

private:
    explicit shared_foo_ptr_t(std::shared_ptr<Foo>&& foo) :
        m_foo_ptr(foo)
    {
    }

    std::shared_ptr<Foo> m_foo_ptr;
};

// helper function that looks like std::make_shared
template<typename type_t>
auto make_shared_foo_ptr() -> std::enable_if_t<std::is_base_of_v<Foo,type_t>, shared_foo_ptr_t>
{
    return shared_foo_ptr_t::create<type_t>();
}


// show function using shared_foo_ptr_t
void fn(const shared_foo_ptr_t& shared_foo_ptr)
{
    shared_foo_ptr->DoSomething();
}

int main()
{
    auto foo_ptr = make_shared_foo_ptr<Derived>();
    fn(foo_ptr);

    //auto bar_ptr = make_shared_foo_ptr<Bar>(); // does not compile as it should

    // allow casting to a normal shared_ptr
    auto shared_ptr = static_cast<std::shared_ptr<Foo>>(foo_ptr);

    // then you have all the other shared_ptr facilities too
    auto derived_ptr = std::dynamic_pointer_cast<Derived>(shared_ptr);
    if ( derived_ptr != nullptr)
    {
        derived_ptr->DoSomething();
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.