中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言面向對象編程中的封裝是什么

發布時間:2022-03-17 09:04:51 來源:億速云 閱讀:244 作者:iii 欄目:開發技術

這篇文章主要介紹“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 <string.h>
#include <stdlib.h>
//控制器對象
//控制器對象屬性
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 <string.h>
#include <stdlib.h>
//控制器對象
//控制器對象屬性
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 <string.h>
#include <stdlib.h>
#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語言面向對象編程中的封裝是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

葵青区| 开原市| 宝丰县| 闽清县| 澳门| 海阳市| 策勒县| 枝江市| 云阳县| 北流市| 明光市| 曲阳县| 县级市| 绥宁县| 三河市| 澄迈县| 大名县| 鄱阳县| 大冶市| 金堂县| 定西市| 卓尼县| 托克托县| 富宁县| 旬阳县| 闻喜县| 铜山县| 濮阳市| 金门县| 大余县| 扎兰屯市| 辽宁省| 紫阳县| 湖北省| 邹城市| 遂昌县| 全椒县| 务川| 沈丘县| 岳西县| 和静县|