- 前言
- 面向对象是什么?
- 面向对象的三大特性
- 封装-隐藏内部实现
- 继承-复用现有代码
- 多态-改写对象行为
开一个专题,记录自己学习OOPC的过程。许多资料都是来源于之前的笔记和摘抄,有些文档和知识点具体的出处不记得了。如果有您的心血并未写明出处,请联系我。
邮箱:kyq18852982072@163.com
微信:18852982072
学了很久的C也用了很久,我一直对程序的架构有着偏执的爱好,可能这是一种偏执病吧。
面向对象是什么?
借用傻孩子的话:
微知识:模块的封装(一):C语言类的封装
- 面向对象是一种思想,基本与所用的语言是无关的。当你心怀面向对象,即便用QBasic也能写出符合面向对象思想的代码,更不用说是C语言了。举一个反例来说,很多人初学C++的时候,并没有掌握面向对象的思想,活生生把类当结构体来用的,也不在少数吧?
2. 面向对象的最基本出发点是“将数据以及处理数据的方法封装在一起”。至于继承、派生、多态之类则是后面扩展的东西。在C语言中,如果用结构体来保存数据,并将处理这些数据的函数与结构体的定义封装在同一个.c文件中,则该.c文件就可以视作是一个类。如果将指向具体函数的函数指针与结构体的其它成员变量封装在同一个结构体中,则该“对象”的使用甚至就与C++相差无几了。
真正关键的是给自己建立面向对象的思维模式和训练自己相应的开发方法,这就需要你去看那些介绍面向对象方法的书了,比如面向对象的思想啊,设计模式阿,UML建模阿。还是那句老话,如果你不知道怎么入门,看《UML+OOPC》。
IOT-OS之RT-Thread(三)— C语言对象化与内核对象管理
面向对象的三大特性 封装-隐藏内部实现封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
也就是说封装的特性
- 对象的外特性(对象能接受哪些消息,具有那些处理能力),
- 而对象的内特性(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。
- 使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
我们来看第一个例子:
当我们只提供Shape.h而将Shape.c进行掩码 *** 作时,对于一个用户(main.c)而言。我们给他提供一个Shape的结构体,也提供了创建(Shape_create), 初始化(Shape_init), 移动(Shape_move)来 *** 作Shape结构体。我们设想的情况是:当他使用这个Shape结构体的时候仅仅只用我们设定给好的方法去 *** 作这个结构体即可。
而现实情况是,在使用该模块的人可能会因为种种原因直接访问甚至修改Shape结构体中的数据。与我们预期假想的使用创建(Shape_create), 初始化(Shape_init), 移动(Shape_move)来 *** 作Shape结构体额意愿已然相违背。结构体里面的成员变量都是public的,如何保护他们使其拥有private属性?
解决办法:使用掩码结构体(Masked Structure)
于是我们来看下一个例子:
在这个例子中,我们可以看到 queue.c 并不需要依赖于queue.h文件。可以单独被编译到。而queue_t 实际上只有一个chMask数组。但是在queue.c中我们把queue_t当作__queue_t 来使用,这个对于外部的用户来说是不可见的,因为queue.h中根本没有定义这个类型。
可以这么理解,用户定义一块缓冲区传递给lib库,而库则将这块缓冲区看成是 __queue_t 结构体完成各种 *** 作。用户只能通过接口函数访问内部,用户对结构体的 *** 作是非法的(因为对于用户来说,它只是定义了一个 uint8_t 数组并不是结构体,所以不能对结构体进行 *** 作。
于是摘抄一下 傻孩子的这个宏 *** 作 。。。 或者OOPC 书上也有相关的定义 只是名字改了一下而已。
这段宏 *** 作与上面掩码结构是一样的。只不过是把这样的 *** 作抽象出来了。
#define __EXTERN_CLASS_OBJ( __TYPE, __OBJ ) \
extern union { \
CLASS(__TYPE) __##__OBJ; \
__TYPE __OBJ; \
};
#define EXTERN_CLASS_OBJ(__TYPE, __OBJ) \
__EXTERN_CLASS_OBJ( __TYPE, __OBJ )
#define __EXTERN_CLASS(__NAME,...) \
/*typedef union __NAME __NAME; */ \
union __NAME { \
__VA_ARGS__ \
uint_fast8_t __NAME##__chMask[(sizeof(struct{\
__VA_ARGS__
#define EXTERN_CLASS(__NAME, ...) __EXTERN_CLASS(__NAME, __VA_ARGS__)
#define END_EXTERN_CLASS(__NAME, ...) \
}) + sizeof(uint_fast8_t) - 1) / sizeof(uint_fast8_t)];\
};
#define DECLARE_CLASS(__NAME) \
typedef union __NAME __NAME;
#define __DEF_CLASS(__NAME,...) \
/*typedef union __NAME __NAME; */ \
typedef struct __##__NAME __##__NAME; \
struct __##__NAME { \
__VA_ARGS__
#define DEF_CLASS(__NAME, ...) __DEF_CLASS(__NAME, __VA_ARGS__)
#define __END_DEF_CLASS(__NAME, ...) \
}; \
union __NAME { \
__VA_ARGS__ \
uint_fast8_t __NAME##__chMask[(sizeof(__##__NAME) + sizeof(uint_fast8_t) - 1) / sizeof(uint_fast8_t)];\
};
#define END_DEF_CLASS(__NAME, ...) __END_DEF_CLASS(__NAME, __VA_ARGS__)
#define __CLASS(__NAME) __##__NAME
#define CLASS(__NAME) __CLASS(__NAME)
继承-复用现有代码
继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继承其它类的全部描述,同时可修改和扩充。继承具有传递性。继承分为单继承(一个子类只有一父类)和多重继承(一个类有多个父类)。类的对象是各自封闭的,如果没继承性机制,则类对象中数据、方法就会出现大量重复。继承不仅支持系统的可重用性,而且还促进系统的可扩充性。
多态-改写对象行为
多态性是指对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动的现象。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:RT-Thread系统中的设备:抽象设备具备接口统一的读写接口。串口是设备的一种,也应支持设备的读写。但串口的读写 *** 作是串口所特有的,不应和其他设备 *** 作完全相同,例如 *** 作串口的 *** 作不应应用于SD卡设备中。C语言的多态性用到了函数指针,而且在结构体中封装了函数指针,封装函数指针的结构体可以成为虚函数表。
下面我来举个例子:
在当前例子中 我们仍然用掩码结构体来做封装 只不过在这个封装的结构体中有一个ops 虚函数表。
类总是会提供一些方法,可以让我们很方便的使用。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)