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