C++反射の実現

13893 ワード

前言
反射の概念:
プログラムが実行されている間に、プログラム自体の状態や動作にアクセス、検出、変更する能力を指します.wikipedia
簡単に言えば、自己記述と自己制御の能力である.鏡を連想すれば、自分の動作、自分の外見を含めて、鏡を通じて自分を見ることができます.唯一の違いは、コンピュータ言語の反射能力には、見た自分に対する措置が含まれていることです.
はんしゃの作用
コンピュータプログラミング言語では、反射メカニズムを使用できます.
  • は、属性、方法
  • を含むタイプの情報を取得する.
  • 動的呼び出し方法
  • 動的構築オブジェクト
  • プログラムセットから取得するタイプ
  • 反射の欠点
  • 性能:反射は、直接呼び出しよりも常に遅い解釈動作であると理解できる.もちろん、パフォーマンスの問題の程度は制御できますが、プログラムが少ない場所で使用されている場合、パフォーマンスは問題ではありません.
  • 反射はプログラム内部で実際に発生したことをぼやけており,直接コードよりも複雑である.

  • 欠点はその長所を隠すことができず、異なるシーンに対して合理的な技術を使うことが最高の境地である.
    反射の使用シーン
  • シーケンス化(Serialization)およびデータバインディング(Data Binding)
  • リモートメソッド呼び出し(RMI)
  • オブジェクト/リレーショナルデータマッピング(O/R mapping)
  • c++の反射について
    Javaは反射機構を原生的にサポートしており,Classクラスによってクラスオブジェクトを名前で取得し,さらに操作できることを知っている.Pythonは反射機構もサポートしており,globals()でオブジェクトmapを取得することもできるし,inspectモジュールで自省する方法を提供することもできる.でもC++は?C++オリジナルは反射機構をサポートせず,RTTI(ランタイムタイプ識別)もタイプの判断のみを提供した.
    開閉原則は設計モードの原則の一つであり,修正に対しては閉鎖であり,拡張に対しては開放である.一般的に,クラスを抽象化し,抽象的なクラスに対してプログラミングする必要がある.多くの設計モードでは、これを満たすために、文字列とタイプをマッピングするプロファイルを使用することがよくあります.その後、反射メカニズムによって文字列に対応するオブジェクトが得られ、自動アセンブリは拡張しやすい目的を達成しました.
    本論文では,主に2つの小さなシーンがC++反射を実現する方法を紹介する.実際、C++は反射をよくサポートしているわけではありません.動的および静的反射をサポートするには、ゆっくり探す必要があります.私はいくつかの資料を提供します.
    C++11 reflection library RTTRライブラリBoost.MirrorライブラリMirror C++reflection library
    本論文では,C++における簡単な反射をどのように実現するかを論じた.
    シーン
  • C++シーケンス化、逆シーケンス化.シーケンス化とは,オブジェクトプログラミングバイナリの形式をディスクに格納したり,ネットワークを介して別のマシンに転送したりすることである.逆シーケンス化はシーケンス化の逆過程である.しかし,この逆過程では,文字列に基づいてバイナリストリームをどのようなタイプのオブジェクトに変換するかを判断しなければならない.
  • ファクトリモードは、文字列に基づいて所望のオブジェクトを取得することが多い.しかし,開閉の原則を満たすために,工場クラスで生産関数を絶えず修正して異なるタイプを拡張することはできない.このとき,反射を利用して抽象クラスを用いる必要がある.

  • インプリメンテーション
    アイデアは次のとおりです.
  • map、マッピング文字列、および生産関数
  • を使用する
  • 新しいタイプを構築するたびに、mapに生産関数を
  • に登録する.
  • 工場関数はmapによって生産関数を獲得し、異なるオブジェクト
  • を構築する.
    シナリオ1
  • mapはObject抽象親に
  • 格納
  • ClassInfoヘルパータイプを使用してサブクラスオブジェクト(サブクラスオブジェクトのコンストラクション関数を含む)
  • を保存する.
  • mapマッピング構造->サブクラス名:ClassInfo*
  • // Reflex.h 
    class Object{
    public:
        Object(){}
        virtual ~Object(){}
        static bool Register(ClassInfo *ci); //     
        static Object *CreateObject(string name);
    }
    
    using ObjectConstructorFn = Object *(*)(void); //       
    class ClassInfo {
    public:
        ClassInfo(const string classname, ObjectConstructorFn ctor)
            :class_name_(classname), m_object_constructor_(ctor) {
            Object::Register(this); //    Object 
        }
    
        virtual ~ClassInfo(){};
        Object *CreateObject() const { //            
            return m_object_constructor_ ? (*m_object_constructor_) : 0;
        }
    
        const string GetClassName() const {return class_name_;}
        ObjectConstructorFn GetConstructor() {return m_object_constructor_;} 
    
    private:
        string class_name_;
        ObjectConstructorFn m_object_constructor_; //       
    }
    
    
    ==============================================================
    // Reflex.cpp
    #include "Reflex.h"
    
    static unordered_map<string, ClassInfo *> *class_map = nullptr; //         
    
    bool Object::Register(ClassInfo *ci) {
        if (!class_map) {
            class_map = new unordered_map<string, ClassInfo *>();
        }
    
        if (ci) {
            //        
            string c_name = ci -> GetClassName();
            if (class_map -> find(c_name) == class_map -> end()) {
                class_map[c_name] = ci;
            }
            return true;
        }
    
        return false;
    }
    
    Object *Object::CreateObject(string name) {
        //           classinfo createobject
        if (class_map -> find(name) != class_map.end())
            return class_map[name] -> CreateObject();
    
        return nullptr;
    }
    
    
    ==============================================================
    // test.cpp
    class A : public Object {
    public:
        A(){}
        ~A(){}
        ClassInfo *GetClassInfo const{ return &m_class_info_;}
    
        //        
        static Object *CreateObject() {
            return new A;
        }
    
    protected:
        static ClassInfo m_class_info_;
    }
    
    //       ,       Object 
    ClassInfo A::m_class_info_("A", A::CreateObject);
    
    int main() {
        Object *obj = Object::CreateObject("A");
        delete obj;
    
        return 0;
    }
    

    上のコードは簡単な反射機構を実現したが,まだ十分ではない.クラスを構築するたびに、多くの重複コードを書く必要があります.C++のマクロは、重複コードを簡略化するための良いツールを提供しています.次のようになります.
    // Reflex.h
    
    //       class_info      CreateObject、GetClassInfo  
    #define DECLEAR_CLASS(name) \
        protected: \
            static ClassInfo m_class_info_; \
        public:
            ClassInfo *GetClassInfo const; \
            static Object *CreateObject(); \
    
    //   CreateObject GetClassInfo    
    #define IMPLEMENT_CLASS_COMMON(name, func) \
        ClassInfo name::m_class_info_((#name), (ObjectConstructorFn) func); \
    
        ClassInfo *name::GetClassInfo() const \
        { return &name::m_class_info_;}
    
    // classInfo       
    #define IMPLEMENT_CLASS(name) \
        IMPLEMENT_CLASS_COMMON(name, name::CreateObject) \
        Object* name::CreateObject() \
        { return new name;}
    
    ==============================================================
    // test.cpp
    class B : public Object {
        DECLEAR_CLASS(B)
    public:
        B(){}
        ~B(){}
    };
    
    IMPLEMENT_CLASS(B)

    シナリオ2
  • mapは、単一のファクトリクラスに
  • 格納.
  • RegisterActionタイプ完了登録動作
  • を定義する.
  • 同様にマクロを用いて重複コードを
  • 簡略化する.
    //      
    class ClassFactory{
    private:  
        map<string, PTRCreateObject> m_classMap ;  
        ClassFactory(){}; //       
    
    public:   
        void* getClassByName(string className);  
        void registClass(string name, PTRCreateObject method) ;  
        static ClassFactory& getInstance() ;  
    };
    
    //      
    //@brief:              
    ClassFactory& ClassFactory::getInstance(){
        static ClassFactory sLo_factory;  
        return sLo_factory ;  
    }  
    
    //@brief:              
    void* ClassFactory::getClassByName(string className){  
        map<string, PTRCreateObject>::const_iterator iter;  
        iter = m_classMap.find(className) ;  
        if ( iter == m_classMap.end() )  
            return NULL ;  
        else  
            return iter->second() ;  
    }  
    
    //@brief:                         map    
    void ClassFactory::registClass(string name, PTRCreateObject method){  
        m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ;  
    }  
    
    //     
    class RegisterAction{
    public:
        RegisterAction(string className,PTRCreateObject ptrCreateFn){
            ClassFactory::getInstance().registClass(className,ptrCreateFn);
        }
    };
    
    ==============================================================
    
    //test class B
    class TestClassB{
    public:
        void m_print(){
            cout<<"hello TestClassB"<//@brief:          
    TestClassB* createObjTestClassB{
            return new TestClassB;
    }
    //          
    RegisterAction g_creatorRegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB);
    
    ==============================================================
    //           
    
    #define REGISTER(className)                                             \
        className* objectCreator##className(){                              \
            return new className;                                           \
        }                                                                   \
        RegisterAction g_creatorRegister##className(                        \
            #className,(PTRCreateObject)objectCreator##className)
    

    マクロ#マクロ#
    マクロに言及した以上、ここで簡単に復習すると、マクロは#defineによって定義されています.前処理フェーズでマクロ展開を行います.フォーマットは次のとおりです.#define ()
    #define N 2 + 2  //         
    #define N (2 + 2)  //       ,   (2 + 2)
    
    #define area(x) (x) * (x) //                  #               #define Conn(x, y) x##y     //     ,  ,      
    ##             #define ToString(x) #x      //         
    #@           #define ToChar(x) #@x       //       ,      

    まとめ
    反射は多くの場合、使用する必要があり、適用シーンが広く、コードをよく読むことを望んでいます.反射メカニズムを自分のエンジニアリングに使用し,いくつかの設計の良いフレームワークを実現した.また,C++マクロの使用はいくつかの重複コードを極めて簡略化することができ,注意深く検討することができる.