当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]封装,在C语言编程中,大部分时候用一个函数调用(API)将一个复杂过程的细节屏蔽起来,用户不需要了解细节,只需要调用该函数就能实现相应的行为。

很多程序员小白在刚刚踏入职场,做程序开发工作的时候,经常会被项目经理叫去喝茶。

小白,你写的这代码耦合太严重啦,简直没有设计可言,更不要说扩展性和灵活性,所有的功能都定义在一个类里,这样随着功能的增多,代码就越来越复杂。你赶紧把代码拆分一下,各功能进行一下代码封装。

1那什么是封装呢?

封装,在C语言编程中,大部分时候用一个函数调用(API)将一个复杂过程的细节屏蔽起来,用户不需要了解细节,只需要调用该函数就能实现相应的行为。例如吃饭函数,将盛饭,动筷子,夹菜,张嘴,咀嚼,下咽等细节屏蔽起来,我们只需要调用吃饭函数,默认就实现了一遍这样的流程。

面向对象思想中的封装使用更广泛,即一个对象类(C语言中用结构体代替),需要隐藏用户不需要也不应该知道的行为和属性。用户在访问对象时,不需要了解被封装的对象和属性,就能使用该对象类,同时对象类也应该通过权限设置,禁止用户过多地了解被封装的对象属性与行为。

封装的思想都是为了让用户不需要了解对象过多的细节,就能直接通过API来使用对象,从而达到模块化编程,程序员分工合作,各自负责维护自己负责模块对象细节的作用。这个原则普遍存在于现实生活中,在软件开发领域也始终提倡着。

2为什么要进行代码封装?

我们写程序是用来解决问题的,而且要解决的是现实中的问题,所以我们需要将现实问题转化为符号化的问题,而现实中的问题是由个体所组成的,所以我们将数据和处理数据的方法封装起来形成一个个体,这个个体在问题里面有专门的功能,比如一张纸可以折叠,一支笔可以写,这样有助于我们以自身的角度进行思考分析,这就是面向对象。如果用面向过程的思路,会导致问题与程序之间的转化不好处理,可能使解决问题出现偏差。

封装的过程,其实就是对事物进行抽象的过程,也是对事物进行认识的过程,我们从开始到现在,封装的层次越来越深,处理的问题也越来越复杂。因为我们需要理清复杂问题的内部规律,从而找出解决问题的办法,而深层次的封装使问题恢复成本来的样子就是一种解决办法。所以说封装是在面对软件复杂度增加,开发过程中遇到各种瓶颈时,为了解决这些问题而提出的,通过封装可以达到模块化编程,程序员分工合作,各自负责维护自己负责模块对象细节的作用。当封装的程度达到了一定的水平,就是面向对象的程序设计思想。

3什么是面向对象思想,和面向过程有什么不同?

所谓面向对象的思想其实就是一种在代码编写之上的软件系统结构设计的思想,和语言无关,并不是C++或者JAVA 、Python等语言才有的。面向对象思想,是随着软件系统的复杂度越来越高,面对大规模软件系统设计的问题,而提出的一种管理大型软件系统设计的思想。只是在C语言出现时,计算机软硬件系统还在起步阶段,面向对象的思想尚未发展,因而C语言中缺乏面向对象相关的核心关键词语法的支持。而JAVA、Python等一些1990年代之后问世的语言,受到C++语言影响以及面向对象思想的逐渐流行,在语法层面就提供了面向对象的核心关键词支持,可以说在处理面向对象问题上具有先天优势。虽然C语言不支持很多面向对象的核心关键词,但是随着Linux内核,Ffmpeg,Nginx等大规模以C语言编写的开源软件项目的发展与推广,C语言遇到的软件复杂度增加以及系统设计与系统长期维护的问题,与JAVA、C++编程遇到的复杂度问题是想通的。并且,面向对象思想也是由于开发者们在开发过程中遇到瓶颈才提出来的,这些问题,不管是用C语言编程还是JAVA编程,都会客观存在。因而用C语言模拟JAVA等面向对象的语言,采用面向对象的思想进行系统顶层设计是很有必要的。

面向过程与面向对象的思想用途不同,没有好坏之分。面向对象思想更倾向于程序之上的顶层设计与程序系统结构设计,然后真正要实现一个函数细节的时候,还是需要面向过程地分析细节如何实现,需要初始化哪些变量,注册哪些结构,设置哪些寄存器等面向过程的问题。

4在C语言中实现面向对象的思想

既然面向对象是种思想,任何语言都可以实现,而且这种思想最重要的几个特性是封装,继承,多态。那在C语言中如何实现呢?

在正式介绍C语言实现封装,继承和多态事前,先介绍一下C语言中的几个概念和语法。

4.1基本知识

(1)结构体

在C语言中,常把一个对象用结构体进行封装,这样便于对对象进行操作,比如:

strcut Point{

int x;

int y;

};

结构体可以嵌套。因而可以把一个结构体当成另一个结构体的成员,如:

struct Circle {

struct Point point_;

int radius;

};

该结构体与以下定义完全一样(包括内存布置都一样):

struct Circle {

int x;

int y;

int radius;

};

(2)函数指针

函数指针是指针的一种,它指向函数的首地址(函数的函数名即为函数的首地址),可以通过函数指针来调用函数。

如函数:

int func(int a[], int n);

可以这样声明函数指针:

int (*pFunc)(int a[], int n);

这样使用:

pFunc = func;

(*pFunc)(a, n);【或者PFunc(a, n)】

可以用typedef定义一个函数指针类型,如:

typdef int (*FUNC)(int a[], int n)

可以这样使用:

int cal_a(FUNC fptr, int a[], int n)

{

//实现体

}

(3)extern与static

extern和static是C语言中的两个修饰符,extern可用于修饰函数或者变量,表示该变量或者函数在其他文件中进行了定义;static也可用于修饰函数或者变量,表示该函数或者变量只能在该文件中使用。可利用它们对数据或者函数进行隐藏或者限制访问权限。

4.2封装

在C语言中,可以用结构+函数指针来模拟类的实现,而用这种结构定义的变量就是对象。封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。有两种方法实现封装:

(1) 利用C语言语法。在头文件中声明,在C文件中真正定义它。

这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:

//头文件:point.h

#ifndef POINT_H

#define POINT_H

struct Point;

typedef struct Point point;

point * new_point(); //newer a point object

void free_point(point *point_);// free the allocated space

#endif

//C文件:point.c

#include”point.h”

strcut Point

{

int x;

int y;

};

point * new_point()

{

point * new_point_ = (point *) malloc(sizeof(point));

return new_point_;

}

void free_point(point *point_)

{

if(point_ == NULL)

return;

free(point_);

}

(2) 把私有数据信息放在一个不透明的priv变量或者结构体中。只有类的实现代码才知道priv或者结构体的真正定义。如:

#ifndef POINT _H

#define POINT_H

typedef struct Point point;

typedef struct pointPrivate pointPrivate;

strcut Point

{

Struct pointPrivate *pp;

};

int get_x(point *point_);

int get_y(point *point_);

point * new_point(); //newer a point object

void free_point(point *point_);// free the allocated space

#endif

//C文件:point.c

#include”point.h”

struct pointPrivate

{

int x;

int y;

}

int get_x(point *point_)

{

return point_->pp->x;

}

int get_y(point *point_)

{

return point_->pp->y;

}

//others…..

4.3继承

在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。

比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。

//内存管理类new.h

#ifndef NEW_H

#define NEW_H

void * new (const void * class, ...);

void delete (void * item);

void draw (const void * self);

#endif

//内存管理类的C文件:new.c

#include “new.h”

#include “base.h”

void * new (const void * _base, ...)

{

const struct Base * base = _base;

void * p = calloc(1, base->size);

assert(p);

* (const struct Base **) p = base;

if (base ->ctor)

{

va_list ap;

va_start(ap, _base);

p = base ->ctor(p, &ap);

va_end(ap);

}

return p;

}

void delete (void * self)

{

const struct Base ** cp = self;

if (self && * cp && (* cp) —> dtor)

self = (* cp) —>dtor(self);

free(self);

}

void draw (const void * self)

{

const struct Base * const * cp = self;

assert(self &&* cp && (* cp)->draw);

(* cp) ->draw(self);

}

//基类:base.h

#ifndef BASE_H

#define BASE_H

struct Base

{

size_t size; //类所占空间

void * (* ctor) (void * self, va_list * app); //构造函数

void * (* dtor) (void * self); //析构函数

void (* draw) (const void * self); //作图

};

#endif

//Point头文件(对外提供的接口):point.h

#ifndef POINT_H

#define POINT_H

extern const void * Point; /* 使用方法:new (Point, x, y); */

#endif

//Point内部头文件(外面看不到):point.r

#ifndef POINT_R

#define POINT_R

struct Point

{

const void * base; //继承,基类指针,放在第一个位置,const是防止修改

int x, y; //坐标

}

#endif

//Point的C文件:point.c

#include “point.h”

#include “new.h”

#include “point.h”

#include “point.r”

static void * Point_ctor (void * _self, va_list * app)

{

struct Point * self = _self;

self ->x = va_arg(* app, int);

self ->y = va_arg(* app, int);

return self;

}

static void Point_draw (const void * _self)

{

const struct Point * self = _self;

printf(“draw (%d,%d)”, self -> x, self -> y);

}

static const struct Base _Point = {

sizeof(struct Point), Point_ctor, 0, Point_draw

};

const void * Point = & _Point;

//测试程序:main.c

#include “point.h”

#include “new.h”

int main (int argc, char ** argv)

{

void * p = new(Point, 1, 2);

draw(p);

delete(p);

}

同样,Circle要继承Point,则可以这样:

struct Circle

{

const struct Point point; //放在第一位,可表继承

int radius;

};

4.3多态

可以是用C语言中的万能指针void* 实现多态,接上面的例子:

//测试main.c

void * p = new(Point, 1, 2);

void * pp = new(Circle, 1, 2);

draw(p); //draw函数实现了多态

draw(pp);

delete(p);

delete(pp);

C语言能够模拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject,无线二进制运行环境BREW。采用C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭