千家信息网

C语言面向对象编程中的封装是什么

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要介绍"C语言面向对象编程中的封装是什么",在日常操作中,相信很多人在C语言面向对象编程中的封装是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"C语言面向
千家信息网最后更新 2026年11月02日C语言面向对象编程中的封装是什么

这篇文章主要介绍"C语言面向对象编程中的封装是什么",在日常操作中,相信很多人在C语言面向对象编程中的封装是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"C语言面向对象编程中的封装是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、面向对象基本概念

什么是对象?

此对象非彼对象,虽然有时候此对象又可以是你脑袋中的对象,那让我们从我们误解的对象开始了解吧,虽然我没有,但是用一下自己的直男思维,想想一个对象也是可以滴。那我就进入一下我这个直男脑袋中的对象吧!我有一个对象,这个对象呢,肤白貌美大长腿。用诗中的话就是"皓腕凝霜雪,垆边人似月",美丽的江南女子,谁不喜欢呢。既然是想象,对象不只是仅仅是肤白貌美大长腿,还得爱你,在你寂寞的时候能陪你,在你难过时能在你身边,在你打游戏的时候不会无理取闹。这样的对象多好哇,简直就是梦中情人,可惜只存在想想中(叹气)。

通过上面的例子,想象中的对象,它具有了对象的特征,是不算非常符合人类的特性,易懂。那让我们从上面的例子提取出来对象的普遍特征。

特征一:属性

让我们回到我想象中的对象,对象是怎样的,皓腕凝霜雪,垆边人似月,这个是对象的属性,也就是样子。当然属性不只是样子啦,你可以添加更多的属性,比如声音好听,年龄20岁等等。

特征二:行为

对象具有的动作就是行为。在上面的例子就是,对象非常爱你,难过的时候能陪你,寂寞的时候也能陪你等等,就是这个对象具有的动作,对象能干什么。

对象与类

我们知道了对象是什么,但是你有没有发现这个对象是很广泛的,也就是我想象中的对象不知有一个,符合我想象中对象的特征可以多个,也就是我可以想象又很多个对象。我可以想象有"后宫佳丽三千人",这三个都符合我对象的特征。这些特征就是类,也就是符合我想象的人不只是只有一个,可以有多个,只要这个人符合我想象的特征,她就是在这个类下面的。

那么类与对象的关系又是怎样的?对象就是符合这个类的特例,怎么理解呢?

在我的想象中,符合大美女的属性有很多,但是我不知道具体是谁,但是有一天我在动漫中看见了这个人,她叫小A。小A就是在大美女类下面的一个对象。又有一天,我又碰到一个人,也符合我定义的大美女,这个对象,她叫小B。小A和小B都是符合定义的,也就是在这个类下面的,而小A和小B是一个特例,也就是这个类下面的人,是独一无二的。

面向对象的编程方式

老生常谈,先简单看看面向过程的编程方式是怎样的?设想一个场景,刺激点的。有一天杰哥想你了,打算和你回家一起打电动,那他该怎么做才能邀请到你回家一起打电动?

面向过程的解决方式:简单点的方式简化一下

1:他首先西装革履,打扮的人模狗样,看起来十分帅气,小姐姐看了表示很赞

2:打车到你家

3:盛情邀约

面向对象的解决方式又是怎样的呢:我们看他邀请你涉及几个对象,打车对象,邀请对象,打电动对象,回家对象。那对象是怎么做的呢?那让我们看一下执行顺序:杰哥首先调用了打扮的对象进行了打扮,然后调用打车对象去了你家。到了你家后调用了邀请对象的行为发出了邀请,然后你调用了邀请对象的行为拒绝了杰哥,杰哥调用了情绪的对象的行为,发出了很难过的感觉。

打扮对象:

  • 行为:打扮

打车对象:

  • 属性:打车人

  • 属性:打车地点

  • 行为:上车

邀请对象:

  • 属性:邀请人

  • 属性:邀请结果

  • 行为1:接受

  • 行为2:拒绝

  • 行为3:发出邀请

回家对象:

  • 属性:回家的路

  • 属性:回家的时间

  • 行为:回家

情绪:

  • 属性:程度

  • 行为1:伤心

  • 行为2:难过

  • 行为3:非常难过

通过上面的例子,大概了解到了与面向过程的区别了,面向对象的编程方式的单元是对象,做了什么事情也是以对象执行动作。对象可以被很多对象调用,杰哥可以调用邀请对象中的邀请行为,你也可以调用邀请对象发出拒绝邀请的动作。对象的属性是怎样的,怎样定义是灵活的。

看到上面的例子:面向对象的编程方式=面向过程+面向对象。对象将某一些行为高度封装,然后由指挥官也就是我们自己按照自己的想法按照某个顺序调用(面向过程),在过程中,对象之间会进行一定的数据交互与一定的对象之间的行为调用。

再举个例子:实现一个循迹小车

构建对象:传感器 控制器 小车

小车对象:

  • 属性:当前偏移值

  • 行为:前进 ,后退 ,左转 ,右转

控制器:

  • 属性:输入值,输出值

  • 行为:计算控制值

传感器:

  • 属性:传感器测量值 传感器数量 传感器

  • 行为:测量

//伪代码void Follow_mark(void){        调用传感器对象进行测量,将测量值保存到器测量值        调用控制器对象,将传感器测量值作为输入参数,计算得到结果进行保存        调用小车对象,根据控制传入的控制值,计算当前偏移量,然后根据偏移量调用左转/右转行为}

二、C语言实现面向对象

面向对象的三大特征

了解了面向对象的思想,思想是最重要的,特征是次要的。面向对象具有三大特征,我们或多或少都可以实现,java,python,C++都有,但是C也是可以实现的,只是会比较麻烦,三大特征分别是封装,继承,多态。这三大特征能够帮助实现面向对象的编程,使得面向对象变得更优雅。我们先了解三大特征之三大特征之封装。

面向对象之封装

简介

封装就是将对象的特征进行封装,使之对象的属性和行为只能通过对象进行访问。在上面的例子中,邀请的对象,它的属性与行为是被封装好的,我们只能调用邀请这个对象才能调用邀请对象的行为。

优势:

1、隐藏内部细节,类似函数,只需要调用这个邀请对象的行为发出邀请,而不需要知道里面的底层实现

2、更安全,复用性更好。对象的值都是被封装好的,隐藏掉的,一般是程序员只会提供相应的接口来访问,不能直接修改。复用性,从上面的例子,谁都可以调用对象的行为。

代码实现–基础版

基础版不涉及函数指针与函数表,先学习这个基础版的,理解好面向对象的最简单的封装的实现。

在实现前我们先想一想C到底有什么结构可以实现封装属性,各种属性。这个很简单,结构体嘛,能放各种类型的属性。

行为又怎么体现呢,可以实现各种行为,函数嘛。后面的多态会涉及函数指针,使用函数指针可以实现多态,这都是后面的事情,后面的文章会有简介。

那让我们做一个PID控制器的对象吧,如果不懂的小伙伴也没关系,这个只是控制器,有输入,输出,调试参数,了解这些就行了。具体实现过程,内部细节不懂也没关系,这个不重要,我代码会标出来的。

那我们直接阅读代码,进入困难模式:代码会有比较详细的注释,很容易看懂!

//开始构造对象,既然是控制器,对象必须具有输入,输出,调试参数//属性就是:参数值,输入值,输出值//行为就是:设置参数,查看参数,根据输入计算输出,构造对象,删除对象//属性:用结构体实现#include "stdio.h"#include #include //控制器对象//控制器对象属性typedef struct {    int input;/*控制器输入*/    int ouput;/*控制器输出*/    int P_parameter,I_parameter,D_parameter;/*控制调试参数*/    int Sum_error;/*总偏差,位置式PID积分相关的参数*/    int Last_error;/*上次偏差,位置式PID积分相关的参数*/}controller;//构造对象,初始化controller *Ctor_controller(void){      controller *temp;    temp=(controller *)malloc(sizeof(controller));    //清零    memset(temp,0,sizeof(controller));    return temp;}//删除对象void Del_ontroller(controller * const Me){    if(Me!=NULL) free(Me);}//设置控制器参数void Write_controller(controller * const Me,int P,int I,int D){    Me->P_parameter=P;    Me->I_parameter=I;    Me->D_parameter=D;}//读取控制器参数的值controller Read_controller(const controller * const Me,int P,int I,int D){    return (*Me);}//计算控制器输出,细节看不懂没关系,只需要知道传入的是偏差,就会有输出一个计算结果就行,这个结果能够帮助控制//至于偏差怎么定义什么时候需要用到PID控制器就知道了int Out_controller(controller * const Me,int input){    float   iIncpid=0;    int now_error=input;//当前偏差        Me->Sum_error+=input;     //积分量限幅,方式积分饱和过深        if(Me->Sum_error >500)        {                Me->Sum_error = 500 ;        }        if(Me->Sum_error < -500)        {                Me->Sum_error = -500 ;        }    Me->ouput=Me->P_parameter * input                  // P         +Me->I_parameter * Me->Sum_error                // I         +Me->D_parameter * (now_error-Me->Last_error); // D    Me->Last_error=now_error;                                    // 存储误差,用于下次计算                 return(Me->ouput);           // 返回计算值    }int main(){    controller *test;    controller read_val;    //构造,创建一个对象    test=Ctor_controller();    //设置对象的值    Write_controller(test,1,1,1);    //查看对象的值    read_val=Read_controller(test,1,1,1);    printf("对象 P= %d I=%d D=%d \r\n",read_val.P_parameter,read_val.I_parameter,read_val.D_parameter);    //调用控制器一次:    printf("控制器输出=%d \r\n",Out_controller(test,100));    //删除/销毁一个对象    Del_ontroller(test);}

输出结果:

对象 P= 1 I=1 D=1
控制器输出=300

从上面的例子可以看出来,我直接调用对象,就可以实现封装,设置,查看等,注意使用了需要手动调用删除,不然容易出现内存泄漏,对象的生存时间就是我们程序员自己释放前的时间。

这里是使用堆的方式,容易出现内存溢出的情况,如果是单片机等其他资源较小的单元,可以使用其他方式构造对象,比如下面:对象的生存时间就是主函数的结束时间,编译器替我们释放了对象的资源,不需要我们主动进行释放。

#include "stdio.h"#include #include //控制器对象//控制器对象属性typedef struct {    int input;/*控制器输入*/    int ouput;/*控制器输出*/    int P_parameter,I_parameter,D_parameter;/*控制调试参数*/    int Sum_error;/*总偏差,位置式PID积分相关的参数*/    int Last_error;/*上次偏差,位置式PID积分相关的参数*/}controller;//构造对象,初始化void Ctor_controller(controller * const Me){      //清零    memset(Me,0,sizeof(controller));}//删除对象void Del_ontroller(controller * const Me){    ;}//设置控制器参数void Write_controller(controller * const Me,int P,int I,int D){    Me->P_parameter=P;    Me->I_parameter=I;    Me->D_parameter=D;}//读取控制器参数的值controller Read_controller(const controller * const Me,int P,int I,int D){    return (*Me);}//计算控制器输出,细节看不懂没关系,只需要知道传入的是偏差,就会有输出一个计算结果就行,这个结果能够帮助控制//至于偏差怎么定义什么时候需要用到PID控制器就知道了int Out_controller(controller * const Me,int input){    float   iIncpid=0;    int now_error=input;//当前偏差        Me->Sum_error+=input;     //积分量限幅,方式积分饱和过深        if(Me->Sum_error >500)        {                Me->Sum_error = 500 ;        }        if(Me->Sum_error < -500)        {                Me->Sum_error = -500 ;        }    Me->ouput=Me->P_parameter * input                  // P         +Me->I_parameter * Me->Sum_error                // I         +Me->D_parameter * (now_error-Me->Last_error); // D    Me->Last_error=now_error;                                    // 存储误差,用于下次计算                 return(Me->ouput);           // 返回计算值    }int main(){    controller test;    controller read_val;    //构造,创建一个对象    Ctor_controller(&test);    //设置对象的值    Write_controller(&test,1,1,1);    //查看对象的值    read_val=Read_controller(&test,1,1,1);    printf("对象 P= %d I=%d D=%d \r\n",read_val.P_parameter,read_val.I_parameter,read_val.D_parameter);    //调用控制器一次:    printf("控制器输出=%d \r\n",Out_controller(&test,100));}

代码实现-进阶版

到进阶版,才能够完整的看到封装的实现,封装里面就具有了对象的属性与行为。这里我们通过函数指针访问对象的行为,我们可以通过函数指针访问对象的行为。

那具体行为是怎么实现的呢?实现是通过函数表中的函数指针来访问函数,以此来实现不同函数的调用,从而实现对象的行为。

那让我们看一下代码实现,然后分析指针指向就知道函数是怎么实现的。

头文件 :定义了对象的属性与行为

#ifndef __OOP_H#define __OOP_H//控制器对象struct controller_vtbl;typedef struct {    //对象属性        int input;/*控制器输入*/    int ouput;/*控制器输出*/    int P_parameter,I_parameter,D_parameter;/*控制调试参数*/    int Sum_error;/*总偏差,位置式PID积分相关的参数*/    int Last_error;/*上次偏差,位置式PID积分相关的参数*/    //对象行为指针,通过指针访问函数    struct controller_vtbl *vptr;}controller;//对象的行为所在表,定义对象的行为在这里,通过定义函数指针指向需要实现对象行为的指针struct controller_vtbl{    controller * (*Ctor_controller)(void);    void         (*Del_controller)(controller * const Me);    controller   (*Read_controller)(const controller * const Me);    void         (*Write_controller)(controller * const Me,int P,int I,int D);    int          (*Out_controller)(controller * const Me,int input);};//对象行为函数controller * Ctor_controller(void);void Del_controller(controller * const Me);controller Read_controller(const controller * const Me);void Write_controller(controller * const Me,int P,int I,int D);int Out_controller(controller * const Me,int input);#endif

源文件::具体函数的行为属性的实现就在这里

//开始构造对象,既然是控制器,对象必须具有输入,输出,调试参数//属性就是:参数值,输入值,输出值//行为就是:设置参数,查看参数,根据输入计算输出,构造对象,删除对象//属性:用结构体实现#include "stdio.h"#include #include #include "temp.h"//构造对象,初始化controller * Ctor_controller(void){      controller *ptr;    struct controller_vtbl *table;    ptr=(controller *)malloc(sizeof(controller));    table=(struct controller_vtbl *)malloc(sizeof(struct controller_vtbl));        //清零    memset(ptr,0,sizeof(controller));    table->Ctor_controller=&Ctor_controller;    table->Del_controller=&Del_controller;    table->Out_controller=&Out_controller;    table->Write_controller=&Write_controller;    table->Read_controller=&Read_controller;    ptr->vptr=table;    return ptr;}//删除对象/析构对象void Del_controller(controller * const Me){    if(Me!=NULL)     {        free(Me->vptr);        free(Me);    }}//设置控制器参数void Write_controller(controller * const Me,int P,int I,int D){    Me->P_parameter=P;    Me->I_parameter=I;    Me->D_parameter=D;}//读取控制器参数的值controller Read_controller(const controller * const Me){    return (*Me);}//计算控制器输出,细节看不懂没关系,只需要知道传入的是偏差,就会有输出一个计算结果就行,这个结果能够帮助控制//至于偏差怎么定义什么时候需要用到PID控制器就知道了int Out_controller(controller * const Me,int input){    float   iIncpid=0;    int now_error=input;//当前偏差        Me->Sum_error+=input;     //积分量限幅,方式积分饱和过深        if(Me->Sum_error >500)        {                Me->Sum_error = 500 ;        }        if(Me->Sum_error < -500)        {                Me->Sum_error = -500 ;        }    Me->ouput=Me->P_parameter * input                  // P         +Me->I_parameter * Me->Sum_error                // I         +Me->D_parameter * (now_error-Me->Last_error); // D    Me->Last_error=now_error;                                    // 存储误差,用于下次计算                 return(Me->ouput);                          // 返回计算值    }int main(){    controller *test;    controller read_val;    //构造,创建一个对象,返回对象指针    test=Ctor_controller();    //设置对象的值     test->vptr->Write_controller(test,1,1,1);    //查看对象的值    read_val=test->vptr->Read_controller(test);    printf("对象 P= %d I=%d D=%d \r\n",read_val.P_parameter,read_val.I_parameter,read_val.D_parameter);    //调用控制器一次:    printf("控制器输出=%d \r\n",test->vptr->Out_controller(test,100));    //删除/销毁一个对象    test->vptr->Del_controller(test);}

运行结果:

对象 P= 1 I=1 D=1
控制器输出=300

可以看到,我们这次操作对象并不是直接调用函数,而是通过指针的方式来访问具体的哪个函数,而指针是在创建的对象里面的,这样就可以直接通过对象来访问它的行为。

后面实现多态也是使用了函数指针的方式,在多态里面这里的指针与行为表有了它自己的名字,就是虚指针与虚表。

到此,关于"C语言面向对象编程中的封装是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

对象 控制 行为 控制器 属性 参数 输出 函数 封装 就是 指针 特征 偏差 方式 面的 输入 结果 编程 例子 积分 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海挚品互联网科技有限公司 百单网互联网科技有限公司怎么样 美国互联网保险保险科技 互联网中国科技 互联网未来科技 互联网科技媒体 伴你行互联网科技有限公司 互联网科技的未来发展 中正互联网科技招聘 中国最先进互联网科技公司 以后互联网后是啥科技 互联网科技教育视频 中化能源互联网科技招聘 栖莱科技互联网股份有限公司 厦门千工互联网科技有限公司 滨湖区互联网智能科技产品有哪些 山东有哪些互联网科技公司 35岁以上互联网科技行业 南京一网一红互联网科技有限公司 互联网时代高科技布局 百单网互联网科技有限公司 科技互联网产品 关于新基建和互联网科技 互联网科技ppt模板 沃里互联网科技 互联网金融科技名词解释 上海同邻互联网科技有限公司规模 保山浩联互联网科技有限公司 互联网大会出现的黑科技 互联网科技快速发展优美句子
0