当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]封装,在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语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。

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

嵌入式开发作为信息技术领域的重要分支,其涉及的语言种类繁多,各具特色。这些语言的选择取决于目标平台的特性、性能需求、开发者的熟练程度以及项目的具体要求。本文将详细介绍几种常见的嵌入式开发语言,包括C语言、C++、汇编语言...

关键字: 嵌入式开发 C语言

Java语言和C语言是两种不同的编程语言,它们在语法、特性和应用领域上有许多差别。下面将详细介绍Java语言和C语言之间的差异以及它们各自的技术特点。

关键字: Java语言 C语言 编程

嵌入式系统是一种专门设计用于特定应用领域的计算机系统,它通常由硬件和软件组成,并且被嵌入到其他设备或系统中,以实现特定的功能。在嵌入式系统的开发过程中,选择适合的编程语言是至关重要的。C语言是一种被广泛应用于嵌入式系统开...

关键字: 嵌入式 计算机 C语言

C语言是一种广泛应用于软件开发领域的编程语言。它是由贝尔实验室的Dennis Ritchie在20世纪70年代初创建的,旨在为UNIX操作系统的开发提供一种高级编程语言。C语言具有简洁、高效、可移植性强等特点,因此成为了...

关键字: C语言 操作系统 应用程序

嵌入式系统是现代生活中无处不在的一部分。它们包括了我们的家电、汽车、智能手机、医疗设备等等。这些系统的工作必须高效、可靠,因为它们往往控制着生活中的关键方面。而C语言作为一种广泛用于嵌入式系统开发的编程语言,其质量和稳定...

关键字: 嵌入式系统 C语言 编程

在嵌入式系统开发领域中,C语言是使用最广泛的编程语言之一。它具有高效、灵活和可移植的特点,成为嵌入式系统设计师的首选语言。本文将介绍C语言编程的基本概念、特点以及在嵌入式系统开发中的应用。

关键字: 嵌入式系统 C语言 编程

C语言编译器是一种用于将C语言源代码转换为可执行程序的软件工具。它的主要功能是将C语言代码翻译成机器语言,以便计算机能够理解和执行。C语言编译器通常包括预处理器、编译器、汇编器和链接器等多个组件,它们协同工作以完成编译过...

关键字: C语言 编译器 Microsoft Visual C++

仿真的概念其实使用非常广,最终的含义就是使用可控的手段来模仿真实的情况。在嵌入式系统的设计中,仿真应用的范围主要集中在对程序的仿真上。

关键字: 单片机 仿真器 程序

Matlab和C语言的区别是:1、用途不同;2、语法不同;3、运行速度不同;4、可移植性不同;5、代码管理不同。Matlab是一种数值计算和科学计算工具

关键字: matlab语言 C语言 系统编程

单片机是一种集成电路,它包含了中央处理器、存储器、输入输出接口和时钟等基本部件。单片机广泛应用于各种电子设备中,如家用电器、汽车电子、医疗设备等。单片机的使用领域已十分广泛,如智能仪表、实时工控、通讯设备、导航系统、家用...

关键字: 单片机编程 单片机 C语言
关闭
关闭