首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将shared_ptr从一个父类转换到另一个父类?

如何将shared_ptr从一个父类转换到另一个父类?
EN

Stack Overflow用户
提问于 2017-10-16 15:45:14
回答 2查看 1.8K关注 0票数 1

我正在重新工作我的游戏引擎使用smart-pointers。我有一个Object类,所有东西都是从它继承的。我有一个可呈现的GameObject,因此它继承自IRenderable (一个定义纯虚拟呈现函数的类),不继承对象。我有一个RenderSystem,它应该把shared_ptr放在场景中的所有IRenderable上。

我遇到的问题是如何将GameObject shared_ptr转换为RenderSystem的IRenderable?

我尝试过的想法:

  • RenderSystem使用shared_ptr of GameObject,但这不起作用,因为它很危险,因为并不是所有的gameObjects都是可呈现的。
  • 让IRenderable从对象继承,这应该允许我从对象继承。这意味着IRenderable不再是一个接口,因为Object包含了其他功能。

这完全可以用原始指针完成,因此,我觉得有一些方法可以用智能指针来实现相同的结果。

示例:

代码语言:javascript
复制
// Object.h
class Object : public enable_shared_from_this<Object> { ... }
// GameObject.h
class GameObject : public Object { ... }
// MeshRenderer.h
class MeshRenderer : public GameObject, IRenderable { 
public:
    void initialize()
    {
         // Not able to cast Object to IRenderable
         RenderSystem::instance().addRenderable(getShared());

         // AND

         // Not able to cast Object to IRenderable

RenderSystem::instance().addRenderable(std::static_pointer_cast<IRenderable>(getShared()));
    }
}
// RenderSystem.h
class RenderSystem 
{
    std::list<std::shared_ptr<IRenderable>> m_renderables;
 public:
    void addRenderable(std::shared_ptr<IRenderable> ptr)
    {
       m_renderables.push_back(ptr);
    }
}

// main.cpp
...
auto meshRenderer = std::shared_ptr<MeshRenderer>();
...
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-16 15:54:59

如下所示:

代码语言:javascript
复制
#include <memory>

// everything is an Object - yuk, but ok, if you wish...
struct Object : std::enable_shared_from_this<Object>
{
};

struct GameObject : Object
{

};

struct IRenderable
{
    virtual void render() {};
};

struct RederableGameObject : GameObject, IRenderable
{
    auto as_shared_renderable() -> std::shared_ptr<IRenderable>
    {
        // builds a new shared pointer to IRenderable which
        // uses the same lifetime control block as me
        return std::shared_ptr<IRenderable>
        {
            this->shared_from_this(),   // where to get the control block
            this                        // what to point to
        };
    }
};

文档:

见构造函数编号(8)

ptr

更新:

这里是一个自由函数从任何对象获取正确的shared_pointer的起点,只要它最终是从std::enable_shared_from_this公开派生的

代码语言:javascript
复制
#include <memory>
#include <type_traits>

namespace notstd
{
    // stuff that I think *should be* std

    using namespace std;

    // a trait to determine whether class T is derived from template
    // Tmpl<...>

    template <typename T, template <class...> class Tmpl>
    struct is_derived_from_template_impl
    {
        static std::false_type test(...);

        template <typename...Us>
        static std::true_type test(Tmpl<Us...> const &);

        using result = decltype(test(std::declval<T>()));
    };

    template <typename T, template <class...> class Tmpl>
    using is_derived_from_template = typename is_derived_from_template_impl<T, Tmpl>::result;

    template <typename T, template <class...> class Tmpl>
    constexpr auto is_derived_from_template_v = is_derived_from_template<T, Tmpl>::value;


    // free function version of shared_from_this

    template<class T> 
    auto shared_from(enable_shared_from_this<T>* p) 
    -> std::shared_ptr<T>
    {
        return p->shared_from_this();
    }

    // specific shared_ptr construction from type T

    template<class T> 
    auto shared_from(T*p) 
    -> enable_if_t
    <
        is_derived_from_template_v
        <
            T, 
            enable_shared_from_this
        >, 
        std::shared_ptr<T>
    >
    {
        return std::shared_ptr<T>(p->shared_from_this(), p);
    }

}

// everything is an Object - yuk, but ok, if you wish...
struct Object : std::enable_shared_from_this<Object>
{
};

struct GameObject : Object
{

};

struct IRenderable
{
    virtual void render() {};
};

extern int emit(const char* str);

struct RederableGameObject : GameObject, IRenderable
{
    auto as_shared_renderable() -> std::shared_ptr<RederableGameObject>
    {
        return notstd::shared_from(this);
    }

    auto as_shared_renderable() const -> std::shared_ptr<const RederableGameObject>
    {
        return notstd::shared_from(this);
    }

    void e() const {
        emit("const");
    }
    void e()  {
        emit("mutable");
    }


};



int main()
{

    auto rgo = std::make_shared<RederableGameObject>();

    // prove it works
    auto p1 = rgo->as_shared_renderable();

    // prove it works with a const object also
    auto p2 = static_cast<const RederableGameObject&>(*rgo).as_shared_renderable();

    p1->e();
    p2->e();
}
票数 3
EN

Stack Overflow用户

发布于 2017-10-16 16:08:40

您不能从static_pointer_cast直接执行shared_ptr<Object>shared_ptr<IRenderable>,因为这些类型是不相关的。

但是可以转换为派生类型,然后允许隐式转换到shared_ptr<IRenderable>

代码语言:javascript
复制
auto p = std::static_pointer_cast<MeshRenderer>(getShared());
std::shared_ptr<IRenderer> q = p;

这将执行从第一个基类到派生类型的显式转换,然后执行到第二基类型的隐式转换。这是静态允许的,因为派生类型已知与两个基相关,但不可能在不相关基之间进行直接转换。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46774156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档