什么是面向对象(OOP)
对象 实体 -> 一类事物的个体
类型 类别
特征:
抽象:对事物进行抽象,属性(一类事物的共同特征)、行为(一类事物共同的行为)。
封装:将抽象出来的属性和行为组合起来,封装成为一个类(结构体)
继承:基类(父类) -> 派生类,子类继承自父类,子类就有了父类的所有属性和行为
多态:在父子对象之间,可以发生多态行为。当有父类指针指向子类对象时,调用父类的行为,会调用子类的行为,从而对同一消息做出不同反应。
封装函数
用结构体+pthis指针封装函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| typedef struct Girl { int age; char name[20]; }Girl; Girl* createGirl(); Girl* createGirlWithArgs(int age, const char name[20]); void girl_destroy(Girl* pthis); void girl_print(Girl* pthis);
int main() { Girl* emptyGirl = createGirl(); Girl* yue = createGirlWithArgs(25, "yue");
return 0; }
Girl* createGirl() { Girl* girl = malloc(sizeof(Girl)); if(!Girl) { return NULL; } return girl; } Girl* createGirlWithArgs(int age, const char name[20]) { Girl* girl = malloc(sizeof(Girl)); if(!Girl) { return NULL; } girl->age = age; strcpy(girl->name, name); return girl; } void girl_destroy(Girl* pthis) { free(pthis); } void girl_print(Girl* pthis) { printf("%d %s\n", pthis->age, pthis-name); }
|
封装成员函数
利用函数指针封装行为函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| typedef struct Girl Girl; typedef struct Girl { int age; char name[20]; void (*destroy)(Girl* pthis); void (*print)(Girl* pthis); }Girl;
Girl* createGirl() { Girl* girl = malloc(sizeof(Girl)); if(!Girl) { return NULL; } girl->print = girl_print; girl->destroy = girl_destroy; return girl; }
int main() { Girl* yue = createGirlWithArgs(25, "yue"); girl_printf(yue); yue->print(yue); return 0; }
|
隐藏pthis指针
用全局变量pthis代替传参,加上带参宏,可实现隐藏传参
多线程可能不安全,感觉不如显式传参
1 2 3 4 5 6 7 8
| Girl* pthis = NULL; #define G_Cast(object) (pthis = (object)) int main() { Girl* yue = createGirlWithArgs(25, "yue"); G_Cast(yue)->print(); return 0; }
|
隐藏属性
通过函数来访问成员变量
1 2 3 4 5 6 7 8 9
| int girl_getage() { return pthis->age; } void girl_setage(int age) { pthis->age = age; }
|
通过在定义一个结构体来封装变量
1 2 3 4
| struct inner{ int age; char name[20]; };
|
封装多文件
通过不同的文件封装不同的类
将inner定义在c文件中,可避免h文件被使用时,调用inner接口访问内部变量
继承实现
其实就是结构体内包含结构体。
两种方式访问,可以直接调用(a.b->c),要对基类比较了解,也可以通过调用基类函数调用(B(a)->c或C(B(a)))。
多态实现
当父类指针指向子类对象时,他会去调用子类函数,而不是父类函数
实现方法虚函数表:
1.定义一个虚函数表结构体
2.将需要的函数填入结构体
3.在初始化对象时,填入指定的函数到虚函数表中
4.通过父类函数传入子类对象指针时,通过虚函数表调用函数,而虚函数表指向的是子类的函数
注意虚函数表必须初始化之后才能调用,不然访问野指针了。
父类自身的函数和虚函数表的函数不一致,同样是虚函数表指向实现函数
子类在被继承,通过子类调用孙类还要再实现一遍虚函数表,而通过父类可以
意义在于可以统一接口
多态多文件
一种类一个文件