2017-10-16 164 views
1

我正在重新使用我的遊戲引擎來使用smart-pointers。我有一個Object類,一切都從繼承。我有一個可以渲染的遊戲對象,因此它繼承自IRenderable(定義純虛擬渲染函數的類),並且不會從對象繼承。我有一個RenderSystem,它應該在場景中持有shared_ptr以適應所有可以進入的狀態。如何將一個shared_ptr從一個父類轉換爲另一個父類?

我的問題是如何將我的GameObject shared_ptr投射到RenderSystem的IRenderable?

想法,我曾嘗試:

  • 渲染系統使用遊戲對象的shared_ptr的,但這並不因爲它是危險的,因爲不是所有的gameObjects是渲染工作。
  • 有IRenderable從Object繼承,應該允許我繼承它。這意味着IRenderable不再是一個接口,因爲Object包含其他功能。

這是完全做到,能夠與原始指針正因爲如此,我覺得有一些方法來實現與智能指針相同的結果

例子:

// 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>(); 
... 
+3

也許是https://stackoverflow.com/q/20219385/103167的副本?看看'std :: dynamic_pointer_cast'不能解決你的問題。 –

+0

我現在就試試。 – Matthew

+0

請注意,shared_ptr很重且很慢。在實際應用中,它主要用於性能無關緊要的地方。 –

回答

3

就像這樣:

#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)

http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

更新:

這裏爲自由函數從任何物體,只要它最終公開從std::enable_shared_from_this

衍生獲取一個正確shared_pointer起點
#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(); 
} 
+0

'return std :: static_pointer_cast (shared_from_this());'也可以。向下轉換爲'* this'的類型,然後允許向另一個基類型隱式轉發。 –

+0

@JonathanWakely同意。但是覺得這個問題明確回答得更好。實際上,在我自己的代碼中,如果T直接從'std :: enable_shared_from_this'派生,我使用一個免費的模板函數'template std :: shared_ptr shared_from(T * self)',並帶有適當的enable-iffing以確保沒有轉換。這是一種可恥的事情,不符合標準。 –

+0

@RichardHodges你介意添加模板版本嗎?因爲我可能需要在其他類中執行相同的功能。 – Matthew

4

您不能直接從shared_ptr<Object>執行static_pointer_castshared_ptr<IRenderable>,因爲這些類型不相關。

但是你可以轉換爲派生類型,則允許的隱式轉換到shared_ptr<IRenderable>

auto p = std::static_pointer_cast<MeshRenderer>(getShared()); 
std::shared_ptr<IRenderer> q = p; 

此執行從第一基類派生類型的顯式轉換,然後隱式轉換到所述第二基本類型。這是靜態允許的,因爲派生類型已知與兩個鹼基都有關,但不相關鹼基之間的直接轉換是不可能的。

相關問題