面向对象与面向过程
- 面向过程
就是把整个业务逻辑分成多个步骤,每步或每一个功能都可以使用一个函数来实现 - 面向对象
对象是类的实例化,此时一个类就内部有属性和相应的方法
封装
在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;
}
继承与抽象类
含有纯虚函数的类,我们一般称之为抽象类。抽象类不能被实例化,实例化也没有意义,唯一的好处就是代码分层公共继承 私有继承 保护继承
组合优于继承?
多态
用父类指针调用子类的成员函数
那就是给结构体的成员变量的函数指针指向不同的函数
深浅拷贝
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,
深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针