面向對象與面向過程
- 面向過程
就是把整個業務邏輯分成多個步驟,每步或每一個功能都可以使用一個函數來實現 - 面向對象
對象是類的實例化,此時一個類就內部有屬性和相應的方法
封裝
??在C語言里實現封裝就是實現一個結構體,里面包括的成員變量和函數指針,然后在構造函數中,為結構體的函數指針賦初值
對于這個函數指針往往會把自身傳入,因為只是在模仿class
#include <stdio.h>
#include <stdlib.h>
struct student
{int height;char* name;void(*add_height)(struct student *, int);
};void ADD_HEIGHT(struct student * stu, int add)
{stu->height += add;
}
struct student * Student(int height,char *name)
{struct student * stu = malloc(sizeof(struct student));if(stu) {stu->height = height;stu->name = name;stu->add_height = ADD_HEIGHT;}return stu;
}
void freeStudent(struct student * stu )
{if(stu) {free(stu);stu = NULL;}
}
int main()
{struct student * stu = Student(180,"LCS");printf("%d\r\n",stu->height);stu->add_height(stu,50);printf("%d\r\n",stu->height);return 0;
}
繼承
- 實現方案一: 子類中嵌套父類結構體指針
C語言模仿繼承就是子類的結構體里嵌套一個父類的結構體
那如何實現類似虛函數的效果呢–修改父類的函數指針的指向就行
#include <stdio.h>#include <stdlib.h>struct animal{/* data */int age;void (*speak)(void);};void cat_speak() {printf("speak miaomiao\r\n");}void dog_speak() {printf("speak wangwang\r\n");}struct cat {struct animal * anm;int like_nothing;};struct dog {struct animal * anm;int like_eat_shit;};struct animal* Animal(int age) {struct animal* anm = malloc(sizeof(struct animal));anm->age = age;anm->speak = NULL;return anm;}struct cat* Cat(int age) {struct cat* new_cat = malloc(sizeof(struct cat));new_cat->anm = Animal(age); // 這就意味著等會你釋放內存是真麻煩new_cat->like_nothing = 1;new_cat->anm->speak = cat_speak;return new_cat;}struct dog* Dog(int age) {struct dog* new_dog = malloc(sizeof(struct dog));new_dog->anm = Animal(age); // 這就意味著等會你釋放內存是真麻煩new_dog->like_eat_shit = 1;new_dog->anm->speak = dog_speak;return new_dog;}int main(){struct cat* new_cat = Cat(5);struct dog* new_dog = Dog(10);new_cat->anm->speak();new_dog->anm->speak();return 0;}
- 繼承的妙用: struct list_head 雙向鏈表
??當我們想要實現自己的列表的實現 就把自己的鏈表中嵌入這個雙向列表就行 - 實現方案二: 父類提供一個void * 私有指針 不同的子類把void * 做不同的實現
#include <stdio.h>
#include <stdlib.h>// 基類定義
typedef struct {int age;void (*speak)(void*); // 虛函數指針void* private_data; // 用于存儲子類特定數據
} Animal;// Cat的私有數據結構
typedef struct {int like_nothing;
} CatPrivate;// Dog的私有數據結構
typedef struct {int like_eat_shit;
} DogPrivate;// 實現虛函數:貓叫聲
static void cat_speak(void* obj) {CatPrivate* private_data = ((Animal*)obj)->private_data;printf("Cat says: miaomiao, like_nothing=%d\n", private_data->like_nothing);
}// 實現虛函數:狗叫聲
static void dog_speak(void* obj) {DogPrivate* private_data = ((Animal*)obj)->private_data;printf("Dog says: wangwang, like_eat_shit=%d\n", private_data->like_eat_shit);
}// 創建Animal實例
Animal* create_animal(int age, void (*speak_func)(void*), void* private_data) {Animal* animal = malloc(sizeof(Animal));animal->age = age;animal->speak = speak_func;animal->private_data = private_data; // 設置私有數據return animal;
}// 創建Cat實例
Animal* create_cat(int age) {CatPrivate* cat_private = malloc(sizeof(CatPrivate));cat_private->like_nothing = 1; // 設定Cat私有數據Animal* animal = create_animal(age, cat_speak, cat_private);return animal;
}// 創建Dog實例
Animal* create_dog(int age) {DogPrivate* dog_private = malloc(sizeof(DogPrivate));dog_private->like_eat_shit = 1; // 設定Dog私有數據Animal* animal = create_animal(age, dog_speak, dog_private);return animal;
}int main() {Animal* new_cat = create_cat(5);Animal* new_dog = create_dog(10);// 調用虛函數new_cat->speak(new_cat);new_dog->speak(new_dog);// 清理資源free(((CatPrivate*)new_cat->private_data));free(((DogPrivate*)new_dog->private_data));free(new_cat);free(new_dog);return 0;
}
-
繼承與抽象類
??含有純虛函數的類,我們一般稱之為抽象類。抽象類不能被實例化,實例化也沒有意義,唯一的好處就是代碼分層 -
公共繼承 私有繼承 保護繼承
-
組合優于繼承?
多態
??用父類指針調用子類的成員函數
??那就是給結構體的成員變量的函數指針指向不同的函數
深淺拷貝
??淺拷貝只是對指針的拷貝,拷貝后兩個指針指向同一個內存空間,
??深拷貝不但對指針進行拷貝,而且對指針指向的內容進行拷貝,經深拷貝后的指針是指向兩個不同地址的指針