文章目录
文章参考
https://blog.youkuaiyun.com/weixin_38403778/article/details/82290139
https://blog.youkuaiyun.com/juS3Ve/article/details/78547003
大纲
面向对象的封装、继承和多态
解释面向对象封装、继承、多态的原理,并举了吃饭的例子,比如婴儿是拿奶瓶,而其他人是拿筷子。这边会进一步解释派生类覆盖上层类函数。
继承
学过面向对象语言的人基本都可以理解什么是继承,但我们为什么要使用继承?
很多人说继承可以使代码得到良好的复用,当然这个是继承的一个优点,但代码复用的方法除了继承还有很多,而且有些比继承更好。我认为使用继承最重要的原因是继承可以使整个程序设计更符合人们的逻辑,从而方便的设计出想要表达的意思。比如我们要设计一堆苹果,橘子,梨等水果类,使用面向对象的方法,我们首先会抽象出一个水果的基类,而后继承这个基类,派生出具体的水果类。如果要设计的水果很多,我们还可以在水果基类基础上,继续生成新的基类,比如热带水果类,温带水果类,寒带水果类等,而后再继承这些基类。这样的设计思想就相当于人类的分类思想,简单易懂,而且设计出来的程序层次分明,容易掌握。
既然继承这么好,那该如何使用继承?
继承虽好但不能滥用,否则设计出来的程序会杂乱不堪。根据上面的介绍,可以发现继承主要用来定义一个东西是什么,比如热带水果是水果,菠萝是热带水果等,即继承主要用来设计一个程序的类的框架,将所要设计的东西用继承来设立一个基本结构。如果想为一个类添加一个行为或格外的功能,最好是使用组合的方式。如果想了解组合的方式,可以看一下比较著名的策略模式。
封装
封装是什么?
在C++中,比较狭隘的解释就是将数据与操作数据的方法放在一个类中,而后给每个成员设置相应的权限。从大一点的角度来说,封装就是将完成一个功能所需要的所有东西放在一起,对外部只开放调用它的接口。
为什么要封装?
我认为模块化设计是封装的本质原因。
对软件设计或其他工程设计,特别是比较复杂的工程,一般都是模块化设计。模块化设计的好处就是可以将一个复杂的系统拆分成不同的模块。每一个模块又可以独立的设计,调试,这就让多人一起做一个复杂的工程成为现实。如果想做到模块化设计,封装是不可缺少的一部分。一个好的模块,比如一块inter的CPU芯片,它有强大的功能,虽然我们不知道它内部是如何实现的,但却可以很好的使用它。
多态
什么是多态?
多态简单的说就是“一个函数,多种实现”,或是“一个接口,多种方法”。多态性表现在程序运行时根据传入的对象调用不同的函数。
C++的多态是通过虚函数来实现的,在基类中定义一个函数为虚函数,该函数就可以在运行时,根据传入的对象调用不同的实现方法。而如果该函数不设为虚函数,则在调用的过程中调用的函数就是固定的。比如下面一个例子
C语言实现封装、函数指针
以大象进冰箱例子,解释对象思维和过程思维的差异。
过程式
- 冰箱门打开
- 大象走进去
- 大象关上门
- 严格按照时间式的思维步骤去执行,仿佛自己是统治者,每一步都严格执行
OO思想
-
如果自己是冰箱需要做什么?
提供打开冰箱门的方法(可以理解为接收数据的接口receive),不需要担心是谁放进冰箱(不考虑谁提供的数据)
-
如果自己是大象需要做什么?
提供发送数据的接口(send),不需要考虑具体的目的地
讲C语言如何模拟C++的类,但是其实我们只是想用对象式思想,而不是为了追求形式上的模拟
从一个命令解析器的案例开始
如果我们要做一个命令解析器,输入一个命令,执行一个函数,我们要怎样做?是单纯的switch case吗?
这样做的问题是什么?我们应该如何改进?
过程化程序设计
采用封装思想设计
实际案例
https://blog.youkuaiyun.com/jus3ve/article/details/78599003
含很多模块的软件初始化
实际案例-uboot启动初始化部分
{//---arch/arm/lib/board.c 大部分硬件初始化, 调用主循环main_loop(见common/main.c)
init_fnc_t *init_sequence[] = {
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage,
#ifdef CONFIG_OF_CONTROL
fdtdec_check_fdt,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_BOARD_POSTCLK_INIT
board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
NULL,
};
void board_init_r(gd_t *id, ulong dest_addr)
{
board_init(); /* Setup chipselects */
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop(); //调用主循环main_loop
}
}
void board_init_f(ulong bootflag)
{
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { //大部分硬件初始化
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
}
}
一个嵌入式图形框架的C面向对象
我十三年前写的单片机代码,板子上面有一个LCD,显示多个菜单,按下每个菜单后,执行一个不同的函数?
应该如何实现?
过程式
OO思想
.C语言实现继承和多态,模拟虚函数
提炼软件的中间层
综合案例,对象式思维锻炼
训练对象式思维的综合实例,Linux的各种复杂的I2C、SPI、USB、PCI用对象式思维,缓解各模块的耦合,实现驱动框架最大程度的可复用,和减少具体底层驱动的工作量。