本文参考:
一、封装
封装的本质就是将数据和方法集中到一个对象中,c++或者java使用的是class来实现。c语言中可以使用struct来实现同样的功能。比如下面的程序:
struct student
{
int age;
char *name;
void (*read)(char *);
};
void read_book(char *book)
{
printf("book is :%s", book);
}
int main(void)
{
struct student s1;
s1.age = 10;
s1.name = strdup("xiaoming");
s1.read = read_book;
printf("name: %s age: %d\n", s1.name, s1.age);
s1.read("math");
free(s1.name)
return 0;
}
二、继承
继承可以让子类使用父类的资源,减少重复。父类可以是将子类的共同点抽象出来,提升代码层次。
如何使用c来实现同样的效果,首先肯定还是需要struct来构建父类和子类,同时如果要达到is a的效果,从内存空间来看,也就意味着父类占据了子类内存地址的最开始位置。所以,我们可以按照下面的方式来构造继承。
struct parent
{
void (*func1)(void);
};
struct child
{
struct parent pt;
void (*func2)(void);
};
void test(struct parent *p)
{
p->func1();
}
int main()
{
struct child cd;
test((struct parent *)&cd);
}
三、多态
多态就是在程序运行时,父类指针可以根据具体的子类对象来执行不同的函数行为。c++中一般通过虚函数来实现。c实现多态主要是通过结构体和函数指针。
#include <stdio.h>
// 定义基类
struct Shape
{
void (*draw)(struct Shape*);
};
// 定义派生类
struct Circle
{
struct Shape shape;
int radius;
};
struct Rectangle
{
struct Shape shape;
int width;
int height;
};
void drawCircle(struct Shape *shape)
{
printf("Drawing a circle...\n");
struct Circle *circle = (struct Circle *)shape;
printf("Circle radius is %d\n", circle->radius);
}
void drawRectangle(struct Shape *shape)
{
printf("Drawing a rectangle...\n");
struct Rectangle *rectangle = (struct Rectangle *)shape;
printf("Rectangle width is %d\n", rectangle->width);
printf("Rectangle height is %d\n", rectangle->height);
}
int main()
{
struct Circle circle;
circle.shape.draw = drawCircle;
circle.radius = 10;
struct Rectangle rectangle;
rectangle.shape.draw = drawRectangle;
rectangle.width = 10;
rectangle.height = 20;
struct Shape *shape;
shape = (struct Shape *)&circle;
shape->draw(shape);
shape = (struct Shape *)&rectangle;
shape->draw(shape);
return 0;
}
在Linux内核中数量最多的就是驱动程序代码,因为硬件设备是多种多样的,每种设备都会有对应的驱动程序。Linux对上层的接口都是统一和抽象的,要保证相同的接口最终能够对应到特定的硬件设备,这就需要使用多态的技巧。
include/linux/i2c.h
这个结构体定义了不少函数指针,就是实现多态的关键
struct i2c_driver {
unsigned int class;
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* New driver model interface to aid the seamless removal of the
* current probe()'s, more commonly unused than used second parameter.
*/
int (*probe_new)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
* For the SMBus Host Notify protocol, the data corresponds to the
* 16-bit payload data reported by the slave device acting as master.
*/
void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol,
unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
bool disable_i2c_core_irq_mapping;
};
drivers/i2c/i2c-slave-eeprom.c