LW_OOPC学習02

9398 ワード

文書ディレクトリ
  • 参照
  • LW_OOPC構成
  • LW_OOPCマクロ説明
  • (1)INTERFACE
  • (2)ABS_CLASS
  • (3)CLASS
  • (4)EXTENDSとIMPLEMENTS
  • (5)ABS_CTORおよびEND_ABS_CTOR
  • (6)FUNCTION_SETTING
  • (7)CTORとEND_CTOR
  • (8)SUPER_CTOR
  • (9)DTORおよびEND_DTOR
  • (10)SUPER_PTR
  • (11)SUPER_PTR_2およびSUPER_PTR_3
  • (12)SUB_PTR
  • (13)SUB_PTR_2およびSUB_PTR_3
  • (14)INHERIT_FROM

  • リファレンス
    LW_OOPCマクロ構成及び使用マニュアル金永華
    LW_OOPC構成
    lw_oopc.hには、このようなコードがいくつかあります.
    //    (       ):
    #define LW_OOPC_USE_STDDEF_OFFSETOF     //     C     offsetof
    // #define LW_OOPC_USE_USER_DEFINED_OFFSETOF //           lw_oopc_offsetof 
    
    //           ,     
    // #define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR
    
    //           (            ),      
    // #define LW_OOPC_PRINT_DEBUG_INFO
    

    上のコメントから、LW_OOPCはoffsetwoマクロを使用する必要があります.もしあなたの開発環境がC標準定義のoffsetwoマクロをサポートできれば、何も動かす必要はありません.C標準定義offsetofマクロを開発環境でサポートできない場合は、ユーザー定義lw_を使用することを選択できます.oopc_offsetofマクロ(ユーザーがカスタマイズしたoffsetofマクロさえサポートしていない場合、LW_OOPCはマルチステート特性をうまくサポートできません.残念ながら、LW_OOPCと手を引くしかありません).
    LW_OOPCマクロ説明
    (1)INTERFACE
    INTERFACE(IMoveable)
    {
        void (*move)(IMoveable* t);     // Move  
    };
    

    LW_でOOPCでは,宣言インタフェース,抽象クラス,特定クラスのメソッドメンバーが比較的特殊であり,いずれも関数ポインタタイプのメンバーである.実はLW_OOPCはまさに関数ポインタの特性を借りて,マルチステート機能のシミュレーションを完成させた.
    (2)ABS_CLASS
    ABS_CLASSは、抽象クラスを宣言するために使用されます.たとえば、次のようになります.
    ABS_CLASS(Animal)
    {
        char name[128];     //      (    128   )
        int age;            //      
    
        void (*setName)(Animal* t, const char* name);   //        
        void (*setAge)(Animal* t, int age);             //        
        void (*sayHello)(Animal* t);                    //      
        void (*eat)(Animal* t);                         //      (    ,     )
        void (*breathe)(Animal* t);                     //       (    ,     )
        void (*init)(Animal* t, const char* name, int age);		//         
    };
    

    (3)CLASS
    CLASSは、特定のクラスを宣言するために使用されます.たとえば、次のようになります.
    CLASS(Fish)
    {
        EXTENDS(Animal);		//   Animal   
        IMPLEMENTS(IMoveable);	//   IMoveable  
    
        void (*init)(Fish* t, const char* name, int age);		//         
    };
    

    この例では、Fishクラスを宣言し、クラスにAnimal抽象クラスを継承させ、IMoverableインタフェースを実装します.
    (4)EXTENDSとIMPLEMENTS
    CLASSマクロを紹介するとき、コードにはEXTENDSとIMPLEMENTSの2つのマクロがあります.lw_を表示するとoopc.hのソースコードは、彼らがそっくりであることに気づきます.
    #define IMPLEMENTS(type)	struct type type
    #define EXTENDS(type)		struct type type
    

    継承と実装のキーワードを同時に提供するのは、Javaに詳しい人にLW_を理解しやすくするためだけです.OOPCマクロ.(LW_OOPCでは、継承と実装の宣言を構造体の先頭に書き、継承と実装の宣言を目立つ位置に置くことをお勧めします.コードを読む人がコードをよりよく理解するのに役立ちます)
    (5)ABS_CTORとEND_ABS_CTOR
    ABS_CTORとEND_ABS_CTORは、抽象クラスのコンストラクション関数を定義するために使用されます.たとえば、次のようになります.
    /*        */
    void Animal_setName(Animal* t, const char* name)
    {
        //     name    128   ,       ,    (          )
        strcpy(t->name, name);
    }
    /*        */
    void Animal_setAge(Animal* t, int age)
    {
        t->age = age;
    }
    /*         */
    void Animal_sayHello(Animal* t)
    {
        printf("Hello!   %s,  %d  !
    ", t->name, t->age); } /* */ void Animal_init(Animal* t, const char* name, int age) { t->setName(t, name); t->setAge(t, age); } ABS_CTOR(Animal) FUNCTION_SETTING(setName, Animal_setName); FUNCTION_SETTING(setAge, Animal_setAge); FUNCTION_SETTING(sayHello, Animal_sayHello); FUNCTION_SETTING(init, Animal_init); END_ABS_CTOR

    前述したように、Animalは抽象クラスであり、対応するコンストラクション関数定義にはABS_を使用する必要があると宣言した.CTORとEND_ABS_CTOR.ABS_CTORはAbstract Constructorの略です.
    (6)FUNCTION_SETTING
    ABS_をご紹介しますCTORとEND_ABS_CTORマクロの時、私達はコードの中でまた1つの見知らぬマクロを発見しました:FUNCTION_SETTING、このマクロはLW_OOPCの中の地位は並外れていて、それがなくて、LW_OOPCは存在しない.LW_OOPCのCTORシリーズマクロ(CTOR/END_CTOR,ABS_CTOR/END_ABS_CTOR)は、オブジェクト(C言語ではstruct)にメモリを割り当てる以外に、最も重要なステップは、構造体の関数ポインタメンバーに値を割り当てるプロセスであり、関数バインドとも呼ばれる(C++のダイナミックアセンブリに似ています).関数バインドのプロセスはFUNCTION_SETTINGマクロによって行われます.FUNCTION_SETTINGマクロがどのように実現されているかを見てみましょう.
    #define FUNCTION_SETTING(f1, f2)	cthis->f1 = f2;
    

    ここを見て、読者はきっと心から笑ったはずだ.:)
    (7)CTORとEND_CTOR
    CTORとEND_CTORは、特定のクラスのコンストラクション関数を定義するために使用されます.たとえば、次のようになります.
    /*       */
    void Fish_eat(Animal* t)
    {
        printf("    !
    "); } /* */ void Fish_breathe(Animal* t) { printf(" !
    "); } /* */ void Fish_move(IMoveable* t) { printf(" !
    "); } /* */ void Fish_init(Fish* t, const char* name, int age) { Animal* animal = SUPER_PTR(t, Animal); animal->setName(animal, name); animal->setAge(animal, age); } CTOR(Fish) SUPER_CTOR(Animal); FUNCTION_SETTING(Animal.eat, Fish_eat); FUNCTION_SETTING(Animal.breathe, Fish_breathe); FUNCTION_SETTING(IMoveable.move, Fish_move); FUNCTION_SETTING(init, Fish_init); END_CTOR

    コードから見るとCTOR/END_CTORとABS_CTOR/END_ABS_CTORの使い方はまったく同じで、確かにそうですが、背後には、この2つのマクロの実現方法に少し違いがあります.興味のある読者に、LW_を真剣に検討することをお勧めします.OOPCのソースコード.ここでは、抽象クラスと特定のクラスの概念を明確に区別し、抽象クラスはオブジェクトを作成できないが、特定のクラスは可能であることを簡単に説明する.前に、Animalは抽象クラスであり、Fishクラスは具体的なクラスであることを宣言しました.では、次のことを望んでいます.
    Animal* animal = Animal_new();		//       !
    Fish* fish = Fish_new();			//      !
    

    (8)SUPER_CTOR
    CTOR/END_について説明していますCTORマクロの時、また1つのよく知らないマクロが現れます:SUPER_CTOR.Javaのsuperキーワードとよく似た機能です.SUPER_CTOR(Animal); Animalクラスのコンストラクション関数を呼び出す.(SUPER_CTORは「コンストラクタ」体の先頭に書くことをお勧めします)
    (9)DTORとEND_DTOR
    DTORとEND_DTORは、解析関数を定義するために使用します.たとえば、//Expr_Nodeの解析関数(DTOR/END_DTORは解析関数の意味を実現するために使用されます)
    DTOR(Expr_node)
    	if (--cthis->use == 0)      //       ,     ,    
    	{
    		cthis->finalize(cthis); //            (         )
    		lw_oopc_free(cthis);
    	}
    END_DTOR
    

    ここで、特にC++のthisポインタをシミュレートするために、ABS_CTOR/END_ABS_CTOR、CTOR/END_CTOR、DTOR/END_DTOR定義ブロックではcthisを直接使用できます.
    (10)SUPER_PTR
    SUPER_PTRは「アップシフト」に使用され、オブジェクトポインタを直接親または直接インタフェースにアップシフトします.
    Fish* fish = Fish_new();    //      
    
    //           :   ,   :1 
    fish->init(fish, "   ", 1);          
    
    //  fish     Animal    ,    animals        
    Animal* animal = SUPER_PTR(fish, Animal);  
    
    //  fish     IMoveable      ,    moveOjbs        
    IMoveable* moveFish = SUPER_PTR(fish, IMoveable);
    

    ここで、直接親は分かりやすくて、直接インタフェース、ほほほ、とりあえず私が創始者だと思っています.Fishクラスの宣言コードを見てみましょう.
    CLASS(Fish)
    {
        EXTENDS(Animal);			//   Animal   
        IMPLEMENTS(IMoveable);	//   IMoveable  
    
        void (*init)(Fish* t, const char* name, int age);		//         
    };
    

    ほら:IMPLEMENTS(IMoveable);//IMoverableインタフェースを実装することはFishクラスにとって、IMoverableはその直接インタフェースである.
    (11)SUPER_PTR_2とSUPER_PTR_3
    SUPER_PTR_2とSUPER_PTR_3はSUPER_PTRの高度なバージョンで、それらの役割はSUPER_とPTRは完全に似ていて、すべてアップグレードされていますが、SUPER_PTR_2は2回アップしてSUPER_PTR_3は上に3回回転します.つまりSUPER_PTR_2自分のポインタをおじいさんのポインタに変えるためのSUPER_PTR_3自分のポインタをかつての祖先のポインタに変換するために使用されます.SUPERを見てPTR_2とSUPER_PTR_3のコード:
    #define SUPER_PTR_2(cthis, father, grandfather)	\
    	SUPER_PTR(SUPER_PTR(cthis, father), grandfather)
    
    #define SUPER_PTR_3(cthis, father, grandfather, greatgrandfather)	\
    	SUPER_PTR(SUPER_PTR_2(cthis, father, grandfather), greatgrandfather)
    

    見たでしょうSUPER_PTR_2実は2回SUPER_PTRの重ね合わせ.SUPER_PTR_3は三次SUPER_PTRの重ね合わせ.2回または3回のモデルチェンジでは、プログラムが複雑すぎるため、クラスの継承関係を合理的に組織し、2回のモデルチェンジと3回のモデルチェンジの使用を避けることをお勧めします.
    (12)SUB_PTR
    SUB_PTRは「ダウンシフト」に使用され、親ポインタをサブクラスにダウンシフトします.
    /*      */
    void Fish_eat(Animal* t)
    {
        Fish* fish = SUB_PTR(t, Animal, Fish);
        ……	//       Fish    
        printf("    !
    "); }

    eatメソッドはAnimalのメソッドであり、Fishクラスはこのメソッドを上書きしている.このメソッドの最初のパラメータタイプはAnimal*であるため、Fishクラスを実装するeatメソッドFish_eatの場合、Fishクラスのメンバーにアクセスするには、最初のパラメータを次の方向にFish*に変換する必要があります.これがSUB_です.PTRが成し遂げたこと.
    (13)SUB_PTR_2およびSUB_PTR_3
    SUB_PTR_2とSUB_PTR_3はSUB_PTRの高度なバージョンで、それらの役割はSUB_とPTRは完全に似ていて、すべて下に転換していますが、SUB_PTR_2は下に2回、SUB_PTR_3は下に3回回転します.つまりSUB_PTR_2自分のポインタを孫のポインタに変えるためのSUB_PTR_3自分のポインタを曾孫世代のポインタに変換するために使用されます.SUBを見てPTR_2とSUB_PTR_3のコード:
    #define SUB_PTR_2(selfptr, self, child, grandchild)     \
    	SUB_PTR(SUB_PTR(selfptr, self, child), child, grandchild)
    
    #define SUB_PTR_3(selfptr, self, child, grandchild, greatgrandchild)    \
    SUB_PTR(SUB_PTR_2(selfptr, self, child, grandchild), grandchild, greatgrandchild)
    

    見えたでしょう、SUB_PTR_2実は2回SUB_PTRの重ね合わせ.SUB_PTR_3は三次SUB_PTRの重ね合わせ.2回または3回のモデルチェンジでは、プログラムが複雑すぎるため、クラスの継承関係を合理的に組織し、2回のモデルチェンジと3回のモデルチェンジの使用を避けることをお勧めします.
    (14)INHERIT_FROM
    INHERIT_FROMは、直接親クラスのメンバーにアクセスするために使用されます.たとえば、次のようになります.
    Dog* dog = Dog_new();       //      
    
    //           :   ,   :2 
    dog->init(dog, "   ", 2);  
    INHERIT_FROM(Animal, dog, age) = 3;		//           3 
    printf("     :%d !
    ", INHERIT_FROM(Animal, dog, age)); //

    注意、LW_OOPCの前のバージョンでは、INHERIT_も同時に提供されています.FROM_2とINHERIT_FROM_3この2つのマクロ、INHERIT_FROM_2おじいさんの世代を訪問するためのメンバー、INHERIT_FROM_3祖先のメンバーを訪問するために使用されます.INHERIT_の使用はできるだけ避けるべきだと思います.FROM_2とINHERIT_FROM_3マクロ、なぜなら、これにより、クラスの継承関係に深刻なデータ結合が存在します.(自己クラスは祖父世代、ひいては曽祖父世代のメンバーに直接アクセス可能)これにより、プログラムの理解が困難になり、メンテナンスが困難になる.従って、現在のバージョンでは、INHERIT_FROM_2とINHERIT_FROM_3マクロが削除され、INHERIT_FROMのみが保持される.一般的に、より合理的な関数カプセル化により、現在のクラスを先祖クラスが提供する方法により間接的にアクセスさせることができる祖先クラスのメンバー.現在のクラスで直接おじいさんや祖先のメンバーを訪問する場合は、SUPERを通じてPTR_2とSUPER_PTR_3現在のオブジェクトのポインタを対応する祖先クラスのポインタに変換し、そのポインタでメンバーにアクセスします.