93254
  
  
### 質問内容

タイトル通りなのですが`基底クラスのポインタ変数のインスタンスが何の型にダウンキャストしているかを知る方法が知りたい`方法が知りたいです。`Component`を継承している各クラスで基底クラスに何に継承しているかの情報を残したいのですがそれをするにはどうしたらいいのでしょうか？

### 考えたこと

以下のように実装すこと自体は出来ているのですが、`現状の実装｀部のように列挙型を使っていると、コンポーネントが増えた時(`Component`を継承するクラスが増えたときに)
`if文`で分岐する箇所をちょくちょく増やさにといけないのでので面倒です。

### 現状での問題点

１，コンポーネントが増えた時(`Component`を継承するクラスが増えたときに)
`if文`で分岐する箇所を増えるとゲームループがシンプルじゃなくなるので複雑化します。

２，もっとシンプルなコンストラクタを作成したい。

### 提示画像のついて

これは継承関係の図です。`Component`クラスは継承されるそれぞれのコンポーネントの基底クラスです。  
また`GameObject`は`std::vector<std::shared_ptr<Component>>`変数を持っていてメインループでそれを更新、描画します。

### 試したこと

`Component`クラス型の`//`コメント部のように  
1,`//実装１`,`//実装１`
は`std::type_info`型を用いてどの型の情報を保存しようとしましたがコピーコンストラクタが実装されていないため実装不可です。

2,`//実装3`,`Component`クラスを自体をテンプレート型にするという方法で`std::type_info`型に代入することは出来たのですが、その場合`Component`型の変数を作成する際にどの型に継承するかわからないのに型を決めることになってしまうので実装不可です。

### 現状の実装

`class
Component`部の`//`コメント部`//現状`のように列挙型で基底クラス(`Component`)が何の型に継承しているかの情報を持たせています。

### 実現したいこと

Componentクラスを継承した`std::vector<std::shared_ptr<Component>>`でゲームループで一つづつアップデートやレンダリングする際にif文で分岐したい。

### 知りたこと

`現状の実装`じゃない方法で基底クラスにどの型に継承しているかの情報をどうやって持たせればいいのか知りたい。  
該当コード `///////`部で囲ってる`if()`文

### ソースコード

[code]

    #include <iostream>
    #include <thread>
    #include <future>
    #include <memory>
    #include <ctime>
    #include <unistd.h>
    #include <random>
    #include <time.h>
    #include <iosfwd>
    #include <locale.h>
    
    class GameObject;
    //template<class T> //実装3
    class Component
    {
    public:
    //    Component(Component* c) : info(typeid(*c))    //実装１ Error
    
    /*
        Component(Component* c)・・実装２ Error
        {
            info = typeid(*c);
        }
    */
        //　何に継承しているかを識別するenum
        enum Type
        {
            SpriteRender,
            Transform,
        };
    
        //実装４ (現状)
        Component(GameObject *g,Type t) : type(t),gameObject(g)
        {
    
        }
    
        const Type type;
        const GameObject *gameObject;
        //const std::type_info &info = typeid(T)    //実装3
    
        virtual void f(){ }
    
    };
    
    class Component;
    class GameObject
    {
    
    protected:
        std::vector<std::shared_ptr<Component>> components; //コンポーネント変数
    
    public:
        GameObject()
        {
    
        }
    
        /*
            コンポーネント取得
    
            基底(Component)クラスにアップキャストされたコンポーネントからダウンキャストしたコンポーネント(SpriteRender,Transform　等)を取得
        */
        template<class T>
        std::shared_ptr<T> GetComponent()
        {
            for(std::shared_ptr<Component> c : components)
            {
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
                if(true)
                {
                    return std::dynamic_pointer_cast<T>(c);
                }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
            }
    
            return nullptr; // コンポーネントがない場合の時
        }
    
    
        /*
            コンポーネント設定
    
            基底クラスにアップキャストして格納
        */
        template<class T>
        std::shared_ptr<T> AddComponent()
        {
            if(GetComponent<T>() != nullptr)
            {
                components.push_back(std::make_shared<T>());
    
                return std::dynamic_pointer_cast<T>(components.back());
            }
    
            return nullptr; // コンポーネントがすでにある場合
        }
    
    };
    
    class SpriteRender : public Component
    {
    public:
        SpriteRender(GameObject *g) : Component(g,Component::Type::SpriteRender)
        {
    
        }
    
        void print()
        {
            std::cout<<"class SpriteRender member " <<std::endl;
        }
        
    };
    
    class Transform : public Component
    {
    public:
        Transform(GameObject *g) : Component(g,Component::Type::Transform)
        {
    
        }
    
        void print()
        {
            std::cout<<"class Transform member " <<std::endl;
        }
        
    };
    
    int main()
    {       
    
    
        return 0;
    }
    
[/code]

### 継承関係図

[![画像の説明をここに入力](https://i.stack.imgur.com/3d7bx.png)](https://i.stack.imgur.com/3d7bx.png)


CC BY-SA 4.0
2022-12-30T05:45:59.710
93104
2023-01-16T05:24:30.257
2022-12-30T09:03:29.533
55177
55177
question
c++
基底クラスのポインタ変数のインスタンスが何の型にダウンキャストしているかを知る方法が知りたい


結局何をやりたいのか今一分かりませんし、[UnityEngineの仕様](https://docs.unity3d.com/ScriptReference/GameObject.html)を良く分かっていないので本当にこんな使い方を意図しているのか分かりませんが、列挙子を使わずに派生クラスの型に応じて関数を呼び分けることは技術的には可能です。  
ただし、ダウンキャストを多用するので処理効率は悪いですし、きっとUnityEngineはこんな使い方を意図していないだろうと思います。

コード例：

[code]

    #include <memory>
    #include <vector>
    #include <string>
    #include <iostream>
    
    
    class Component
    {
    public:
        virtual ~Component() = default;
    
        std::string TypeName() const
        {
            return typeid(*this).name();
        }
    };
    
    class Renderer : public Component
    {
    public:
        virtual void Render() = 0;
    };
    
    class SpriteRenderer : public Renderer
    {
    public:
        virtual void Render() override
        {
            std::cout << TypeName() << " - func " << __func__ << "\n";
        }
    };
    
    class Transform : public Component
    {
    public:
        void TransformDirection()
        {
            std::cout << TypeName() << " - func " << __func__ << "\n";
        }
    };
    
    class GameObject
    {
    private:
        std::vector<std::shared_ptr<Component>> m_components;
    
    public:
        template<class T>
        std::shared_ptr<T> AddComponent()
        {
            auto component = std::make_shared<T>();
            m_components.push_back(component);
            return component;
        }
    
        template<class T>
        std::vector<std::shared_ptr<T>> GetComponents() const
        {
            std::vector<std::shared_ptr<T>> components;
            for (auto &component : m_components)
            {
                if (auto componentT = std::dynamic_pointer_cast<T>(component))
                {
                    components.push_back(componentT);
                }
            }
            return components;
        }
    };
    
    int main()
    {
        GameObject  gameObject;
    
        gameObject.AddComponent<SpriteRenderer>();
        gameObject.AddComponent<Transform>();
        gameObject.AddComponent<SpriteRenderer>();
        gameObject.AddComponent<Transform>();
    
        auto spriteRenderers = gameObject.GetComponents<SpriteRenderer>();
        for (auto &spriteRenderer : spriteRenderers)
        {
            spriteRenderer->Render();
        }
    
        // Rendererでもヒットする
        auto renderers = gameObject.GetComponents<Renderer>();
        for (auto &renderer : renderers)
        {
            renderer->Render();
        }
    
        auto transforms = gameObject.GetComponents<Transform>();
        for (auto &transform : transforms)
        {
            transform->TransformDirection();
        }
    }
    
[/code]

Visual Studio 2022での実行結果：

[code]

    class SpriteRenderer - func Render
    class SpriteRenderer - func Render
    class SpriteRenderer - func Render
    class SpriteRenderer - func Render
    class Transform - func TransformDirection
    class Transform - func TransformDirection
    
[/code]


CC BY-SA 4.0
2023-01-08T15:08:17.120
93254
2023-01-08T15:23:24.033
2023-01-08T15:23:24.033
7291
7291
93104
answer


【`type_info` を用いてやりたかったけども→それをうまくやれなかったから現状enumになっている】という件についてですが，  
`type_info` を用いる判定をする手段としては，`Component` クラスに

`virtual bool Is( const type_info &ti ) const { return ti==typeid(Component);
}`

みたいなメソッドを設ければどうでしょうか？  
そしたら，例えば派生型の `Transform` ではこんな感じでしょうか：

`virtual bool Is( const type_info &ti ) const override { return
Component::Is(ti) || (ti==typeid(Transform)); }`

これを用いると型の判定のところは

`if( c->Is( typeid(T) ) )`

みたいな感じの判定になる…と．

※しかしそもそもこういう判定をやってくれるのが `dynamic_cast`
等なわけで，それを自前でやる意味があるのか？と言われると「うーん」という感じですが…  
（例えば `dynamic_cast`
よりも「自前判定+`static_cast`」の方が早いだとかいうような，何かしらの意義があるのでもなければ無意味な気がする）


CC BY-SA 4.0
2023-01-16T05:24:30.257
93372
2023-01-16T05:24:30.257
52236
93104
answer