我正在用 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>();
SharedPtr<Foo> f = ...; SharedPtr<FooDerived> fd = TryCast<FooDerived>(f);
如何实施?
编辑1:较小的文本和标题更改
编辑2:添加模板限制
我会采取这种方法:
#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();
}
}