KEMBAR78
OOP in C - Virtual Function (Chinese Version) | PDF
OOP in C
Virtual Function


              elpam.tw@gmail.com
              elpam@Taiwan, Taipei, 2008
LICENSE
    ●   本投影片授權方式為:
        –   姓名標示─非商業性─相同方式分享 3.0  台灣版
        –   http://creativecommons.org/licenses/by­nc­sa/3.0/tw/




    ●   所有的範例程式皆為 Public Domain




                                           
                                  elpam.tw@gmail.com
About This Slides
    ●   All example was build by 
        –   GCC­4.1.3
        –   GLIB­1.2.10
        –   GMAKE­3.81




                                   
                          elpam.tw@gmail.com
請先覆習一下 Function Pointer 的使用方式




                        
               elpam.tw@gmail.com
Function Pointer

                            /* 2­1.c */
                            typedef void (*FP) ( void );

                            void hello() { printf("hello "); }

                            int main()
                            {
                                 void world() { printf("worldn"); }
      #> ./2­1
                                 FP fp = hello;
     hello world 
                                 fp();
      #>
                                 fp = world;
                                 fp();
                            };
                                  
                        elpam.tw@gmail.com
Function Pointer (cont')
                                  /* 2­2.c */
    ●
        也可以當參數使用                  typedef void (*FP) ( void );

                                  #define ERROR 1

                                  void error_test( FP callback )
                                  {
                                      if( ERROR ){
                                           callback();
                                      }
                                  }

          #> ./2­2                int main()
          error happened          {
          #>                             void error() { printf("error happenedn"); }
                                         error_test( error );
                                  };

                                     
                            elpam.tw@gmail.com
Function Pointer & Structure
                                /* 2­3.c */
                                typedef void (*FP) ( void* );
    ●
        以 Function Pointer      struct A{
                                        int a;               int b;
        的方式實作 Member                    FP  method;
                                };
        Function                void a_real_method( void* p)
                                {
                                        struct A* this = p;
                                        printf("%d,%dn",this­>a,this­>b);
                                }
                                int main()
                                {
           #> ./2­3                     struct A a;
           1,2                          a.a = 1;        a.b = 2;
           #>                           a.method  = a_real_method;
                                        a.method ( &a );
                                };

                                 
                        elpam.tw@gmail.com
Using Previous Slide to Implement Inherit

2­4.c
    ●   方便閱讀,加上一點 ' 命名規則 '
           –   其實是龜毛的 Rule
    ●   PREFIX_init
           –   該物件的 建構子 (Constructor)
    ●   PREFIX_method
           –   該物件的 成員函式 (member function)

                                  
                         elpam.tw@gmail.com
Member Function's Inherit (1)
struct A {                              void A_real_method_a( void* p) {
       int a;                               struct A* this = p;
       FP  method_a;                        printf("this is method_a %dn",this­>a); 
};                                      }
struct B {                              void B_real_method_b( void* p) {
       struct A parent;                     struct B* this = p;
       int b;                               printf("this is method_b %dn",this­>b); 
       FP  method_b;                    }
};
int main()  {                           void a_init( struct A* a)  {
       struct B b;                          a ­> a = 1;
       a_init( &b );                        a ­> method_a = A_real_method_a;
       b_init( &b );                    }
                                        void b_init( struct B* b)  {
         struct A* ap = &b;                 b ­> b = 2;
                                            b ­> method_b = B_real_method_b;
         ap ­> method_a( ap );          }
         b  .  method_b( &b );
};
                                          
                                 elpam.tw@gmail.com
Member Function's Inherit (2)
                                           /* 2­4.c */
                                           int main()
    ●
        Child 如果希望執行 ( 存取 )                {
                                                  struct B b;
        Parent 的函式 ( 變數 ) ,需要                     a_init( &b );   
        先 Cast 成 Parent 再執行 ( 存                   b_init( &b );

        取)                                        struct A* ap = &b;

                                                  ap ­> method_a( ap );
                                                  b  .  method_b( &b );
                                           };



                                             #> ./2­4
                                             this is method_a 1
                                             this is method_b 2

                                             #>
                      elpam.tw@gmail.com
結論
    ●
        我們可以實作 class_init() 時將 class 內的
        member value and member function 都設定好
           –   也就是 ''Constructor'' 
    ●   自已實作 C 不提供的 Member Function!!




                                     
                            elpam.tw@gmail.com
Implement Virtual Function

2­5.c
    ●   Child 的 init 可以將 Parent 的 Member Function
        做改寫的動作,以達到 Virtual Function 的效果
           –   下一頁粉紅色的那一行




                                 
                        elpam.tw@gmail.com
Virtual Function (1)
void A_real_method_a( void* p) 
{
       struct A* this = p;
       printf("this is %s %dn"
                         ,__FUNCTION__,this­>a);          void A_init( struct A* a)
}                                                         {
void B_real_method_a( void* p)                                a ­> a = 1;
{                                                             a ­> method_a = A_real_method_a;
       struct B* this = p;                                }
       printf("this is %s %dn"
                          ,__FUNCTION__,this­>b); 
}                                                         void B_init( struct B* b)
void B_real_method_b( void* p)                            {
{                                                             struct A* a = b;
       struct B* this = p;                                    b ­> b = 2;
       printf("this is %s %dn"                               a ­> method_a = B_real_method_a;
                           ,__FUNCTION__,this­>b);            b ­> method_b = B_real_method_b;
}                                                         }

                                                       
                                             elpam.tw@gmail.com
Virtual Function (2)
    ●
        A_init 一定要比 B_init 先執行
        –   Parent 的 Constructor 需要先執
            行                         /* 2­5.c */
                                                         int main()
                                                         {
                                                              struct B b;
          #> ./2­5                                            A_init( &b );
        this is A_real_method_a 1
        this is B_real_method_a 2                             struct A* ap = &b;
        this is B_real_method_b 2                             ap ­> method_a( ap );
          #>
                                                              B_init( &b );
                                                              ap ­> method_a( ap );
                                                              b  .  method_b( &b );
                                                         };
                                             
                                    elpam.tw@gmail.com
Constructor's Wrapper
            2­6.c




                  
         elpam.tw@gmail.com
Constructor in C (1)
    ●   we use PREFIX_new to replace malloc
        –   所有的物件都以 PREFIX_NEW 產生,以確保
            Constructor 被正確的執行

            struct A{                struct A* A_new()
               int a;                {
               int b;                   struct A* ret = malloc( sizeof(A) );
            };                          ret ­> a = 0;
                                        ret ­> b = 1;
                                        return ret;
                                     }




                                       
                              elpam.tw@gmail.com
Constructor in C (2)
    ●
         以前面的例子


        /* 2­6.c */                                       /* 2­6.c */
        int main()                                        struct B* B_new()
        {                                                 {
                struct B* pb = B_new();                      struct B* pb = malloc( sizeof(B) );
                                                             struct A* pa = pb;
                ((struct A*)pb) ­> method_a( pb );           A_init( pa );
                pb ­> method_b( pb );                        B_init( pb );
                                                             return pb;
        };                                                }



                                                      
                                          elpam.tw@gmail.com
Constructor in C (3)
    ●
        繼承關係越復雜時, PREFIX_new 很難去維護
        –   請試想三層繼承時,開發者希望在第一及第二層之間
            再加上一層物件
    ●
        所以我們需要更有效率的方式來撰寫
        Constructor
        –   GObject 提供了一個有效率的方式




                               
                      elpam.tw@gmail.com
Conclusion
    ●
        以上的 Tips 提供了一種方式來撰寫 Object­
        Oriented 的程式
          –   可自行練習 :)
    ●   相較於 C++ 的繼承,此種方式所撰寫出來的物
        件為靜態形別,所有的 Offset 都是 Compiler 
        Time 已決定好的,所以不會有繼承濫用的問題
          –   執行效率
    ●   但是如果不正確的使用,依舊會造成程式碼難以
 
        閱讀,也容易產生 BUG 
                         elpam.tw@gmail.com

OOP in C - Virtual Function (Chinese Version)

  • 1.
    OOP in C Virtual Function elpam.tw@gmail.com elpam@Taiwan, Taipei, 2008
  • 2.
    LICENSE ● 本投影片授權方式為: – 姓名標示─非商業性─相同方式分享 3.0  台灣版 – http://creativecommons.org/licenses/by­nc­sa/3.0/tw/ ● 所有的範例程式皆為 Public Domain     elpam.tw@gmail.com
  • 3.
    About This Slides ● All example was build by  – GCC­4.1.3 – GLIB­1.2.10 – GMAKE­3.81     elpam.tw@gmail.com
  • 4.
  • 5.
    Function Pointer /* 2­1.c */ typedef void (*FP) ( void ); void hello() { printf("hello "); } int main() { void world() { printf("worldn"); }   #> ./2­1 FP fp = hello;  hello world  fp();   #> fp = world; fp(); };     elpam.tw@gmail.com
  • 6.
    Function Pointer (cont') /* 2­2.c */ ● 也可以當參數使用 typedef void (*FP) ( void ); #define ERROR 1 void error_test( FP callback ) { if( ERROR ){ callback(); } }   #> ./2­2 int main()   error happened  {   #> void error() { printf("error happenedn"); }        error_test( error ); };     elpam.tw@gmail.com
  • 7.
    Function Pointer & Structure /* 2­3.c */ typedef void (*FP) ( void* ); ● 以 Function Pointer  struct A{         int a;               int b; 的方式實作 Member          FP  method; }; Function void a_real_method( void* p) {         struct A* this = p;         printf("%d,%dn",this­>a,this­>b); } int main() {   #> ./2­3         struct A a;   1,2         a.a = 1;        a.b = 2;   #>         a.method  = a_real_method;         a.method ( &a ); };     elpam.tw@gmail.com
  • 8.
    Using Previous Slide to Implement Inherit 2­4.c ● 方便閱讀,加上一點 ' 命名規則 ' – 其實是龜毛的 Rule ● PREFIX_init – 該物件的 建構子 (Constructor) ● PREFIX_method – 該物件的 成員函式 (member function)     elpam.tw@gmail.com
  • 9.
    Member Function's Inherit (1) struct A { void A_real_method_a( void* p) { int a; struct A* this = p; FP  method_a; printf("this is method_a %dn",this­>a);  }; } struct B { void B_real_method_b( void* p) { struct A parent; struct B* this = p; int b; printf("this is method_b %dn",this­>b);  FP  method_b; } }; int main()  { void a_init( struct A* a)  { struct B b; a ­> a = 1; a_init( &b );    a ­> method_a = A_real_method_a;        b_init( &b ); } void b_init( struct B* b)  { struct A* ap = &b; b ­> b = 2; b ­> method_b = B_real_method_b; ap ­> method_a( ap ); } b  .  method_b( &b ); };     elpam.tw@gmail.com
  • 10.
    Member Function's Inherit (2) /* 2­4.c */ int main() ● Child 如果希望執行 ( 存取 )  { struct B b; Parent 的函式 ( 變數 ) ,需要 a_init( &b );    先 Cast 成 Parent 再執行 ( 存        b_init( &b ); 取) struct A* ap = &b; ap ­> method_a( ap ); b  .  method_b( &b ); };   #> ./2­4   this is method_a 1   this is method_b 2       #> elpam.tw@gmail.com
  • 11.
    結論 ● 我們可以實作 class_init() 時將 class 內的 member value and member function 都設定好 – 也就是 ''Constructor''  ● 自已實作 C 不提供的 Member Function!!     elpam.tw@gmail.com
  • 12.
    Implement Virtual Function 2­5.c ● Child 的 init 可以將 Parent 的 Member Function 做改寫的動作,以達到 Virtual Function 的效果 – 下一頁粉紅色的那一行     elpam.tw@gmail.com
  • 13.
    Virtual Function (1) void A_real_method_a( void* p)  { struct A* this = p; printf("this is %s %dn"                          ,__FUNCTION__,this­>a);  void A_init( struct A* a) } { void B_real_method_a( void* p)  a ­> a = 1; { a ­> method_a = A_real_method_a; struct B* this = p; } printf("this is %s %dn"                           ,__FUNCTION__,this­>b);  } void B_init( struct B* b) void B_real_method_b( void* p)  { { struct A* a = b; struct B* this = p; b ­> b = 2; printf("this is %s %dn" a ­> method_a = B_real_method_a;                            ,__FUNCTION__,this­>b);  b ­> method_b = B_real_method_b; } }     elpam.tw@gmail.com
  • 14.
    Virtual Function (2) ● A_init 一定要比 B_init 先執行 – Parent 的 Constructor 需要先執 行 /* 2­5.c */ int main() { struct B b;   #> ./2­5 A_init( &b ); this is A_real_method_a 1 this is B_real_method_a 2 struct A* ap = &b; this is B_real_method_b 2 ap ­> method_a( ap );   #> B_init( &b ); ap ­> method_a( ap ); b  .  method_b( &b ); };     elpam.tw@gmail.com
  • 15.
    Constructor's Wrapper 2­6.c     elpam.tw@gmail.com
  • 16.
    Constructor in C (1) ● we use PREFIX_new to replace malloc – 所有的物件都以 PREFIX_NEW 產生,以確保 Constructor 被正確的執行 struct A{ struct A* A_new()    int a; {    int b;    struct A* ret = malloc( sizeof(A) ); };    ret ­> a = 0;    ret ­> b = 1;    return ret; }     elpam.tw@gmail.com
  • 17.
    Constructor in C (2) ● 以前面的例子 /* 2­6.c */ /* 2­6.c */ int main() struct B* B_new() { {         struct B* pb = B_new();    struct B* pb = malloc( sizeof(B) );    struct A* pa = pb;         ((struct A*)pb) ­> method_a( pb );    A_init( pa );         pb ­> method_b( pb );    B_init( pb );    return pb; }; }     elpam.tw@gmail.com
  • 18.
    Constructor in C (3) ● 繼承關係越復雜時, PREFIX_new 很難去維護 – 請試想三層繼承時,開發者希望在第一及第二層之間 再加上一層物件 ● 所以我們需要更有效率的方式來撰寫 Constructor – GObject 提供了一個有效率的方式     elpam.tw@gmail.com
  • 19.
    Conclusion ● 以上的 Tips 提供了一種方式來撰寫 Object­ Oriented 的程式 – 可自行練習 :) ● 相較於 C++ 的繼承,此種方式所撰寫出來的物 件為靜態形別,所有的 Offset 都是 Compiler  Time 已決定好的,所以不會有繼承濫用的問題 – 執行效率 ● 但是如果不正確的使用,依舊會造成程式碼難以   閱讀,也容易產生 BUG  elpam.tw@gmail.com