日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式微處理器
[導(dǎo)讀]C和C++的最大區(qū)別便是,C++有類,C沒有類的概念。單單這一個(gè)類使得C缺失很多的東西。好在C有結(jié)構(gòu)體,勉強(qiáng)可以當(dāng)0.1個(gè)類來使用。

微信公眾號:二進(jìn)制人生
專注于嵌入式linux開發(fā)。

目錄

前言1、繼承2、封裝偽構(gòu)造函數(shù)3、多態(tài)

前言

我們都知道C語言是一門過程性語言,所謂過程性就是在解決問題時(shí),將問題按步驟分解。

例如,做菜的時(shí)候,先點(diǎn)火,再倒油,接著下菜翻炒,最后加鹽和醬油。但有時(shí)候借鑒面向?qū)ο?/a>的思想來組織代碼,邏輯層次會(huì)更加清晰。

C和C++的最大區(qū)別便是,C++有類,C沒有類的概念。單單這一個(gè)類使得C缺失很多的東西。好在C有結(jié)構(gòu)體,勉強(qiáng)可以當(dāng)0.1個(gè)類來使用。

眾所周知,類有三大特性:封裝、繼承、多態(tài)。我們來看看C語言如何借鑒類的三大特性來更好的組織代碼。

1、繼承

C語言沒有嚴(yán)格意義上的繼承,可以借助結(jié)構(gòu)體嵌套實(shí)現(xiàn)類似于繼承的形式,但始終不盡人意。

struct?parent
{

????int?a;
};
struct?son
{

????struct?parent?p;//兒子繼承父親
????int?b;
};

C++的類可以實(shí)現(xiàn)成員的訪問控制,例如將變量b聲明成private,那么外部就無法訪問。但C的結(jié)構(gòu)體做不到。

在C++里頭,父親的私有成員,兒子是無法訪問的。結(jié)構(gòu)體嵌套也做不到。因?yàn)榻Y(jié)構(gòu)體根本就沒有訪問控制的概念。

對于C++而言,訪問控制實(shí)質(zhì)上是在編譯層做的,我們?nèi)耘f可以通過指針來間接訪問。

例如:

class?Base{
public:
???int?a;
private:
???int?b;
};

盡管b被聲明成私有,但我們?nèi)耘f有辦法訪問它(借助指針繞過語法檢查):

Base?t;
int?*p?=?&t.a;
cout?<1]?<endl;

2、封裝

封裝就是把數(shù)據(jù)和方法打包到一個(gè)類里面。C++的實(shí)現(xiàn)大致如下:

class?類名
{

public:
????公有方法1
????公有方法2
????……
????公有數(shù)據(jù)1
????……
private:
????私有方法1
????私有方法2
????……
????私有數(shù)據(jù)1
????……
};

這樣做的好處是顯而易見的。一個(gè)類實(shí)現(xiàn)了一個(gè)小模塊,使得代碼結(jié)構(gòu)比較清晰。對外接口和數(shù)據(jù)定義成public,允許調(diào)用者直接訪問。內(nèi)部接口和數(shù)據(jù)定義成private,外部不可見。

在 QT 中,為了更好的隱藏一個(gè)類的具體實(shí)現(xiàn),一般是一個(gè)公開頭文件、一個(gè)私有頭文件,私有頭文件中定義實(shí)現(xiàn)的內(nèi)部細(xì)節(jié),公開頭文件中定義開放給客戶程序員的接口和公共數(shù)據(jù)??纯?code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">QObject (qobject.h),對應(yīng)有一QObjectPrivate(qobject_p.h ) ,其他的也類似。

QObject{
public:
????xxx
????xxx
private:
????QObjectPrivate?*?priv;
};

我們可以借助C語言的指針和結(jié)構(gòu)體來實(shí)現(xiàn)方法和數(shù)據(jù)的封裝?;究蚣苋缦拢?/p>

struct?結(jié)構(gòu)體名{
????數(shù)據(jù)1
????數(shù)據(jù)2;
????……
????方法1:
????方法2;
????……
}

在結(jié)構(gòu)體里定義成員變量很容易,直接int a;
在結(jié)構(gòu)體里定義成員函數(shù)要使用函數(shù)指針,比如:

int?(*func)(void?*)

所以,我們把上面的框架具體化就是:

struct?manager{
????int?data1;
????int?data2;
????int?(*operation1)(struct?manager*);
????int?(*operation2)(struct?manager*);
};

實(shí)際上,C++的成員函數(shù)也是通過函數(shù)指針的形式來實(shí)現(xiàn),本質(zhì)上是一致的。我們都知道類的成員函數(shù)和類的成員變量是分開存儲的,同一個(gè)類的所有對象,成員函數(shù)只需要占據(jù)一份地址空間。

在定義結(jié)構(gòu)體之后,函數(shù)指針并沒有賦值,一般我們會(huì)定義一個(gè)結(jié)構(gòu)體初始化函數(shù)來初始化結(jié)構(gòu)體成員,這有點(diǎn)類似于類的構(gòu)造函數(shù),但類的構(gòu)造函數(shù)在創(chuàng)建對象時(shí)自動(dòng)調(diào)用,而我們這個(gè)結(jié)構(gòu)體初始化函數(shù)只能自己手動(dòng)調(diào)用了。

同樣的,對標(biāo)C++的析構(gòu)函數(shù),我們在C語言里頭有一個(gè)去初始化的函數(shù)來完成模塊的去初始化,這種思想不就是一樣的嗎?

static?int?operation1(struct?manager?*manager_ptr)
{
????……
}
static?int?operation2(struct?manager?*manager_ptr)
{
????……
}

偽構(gòu)造函數(shù)

注意,我們把兩個(gè)operation函數(shù)定義成了static,這樣子文件之外的函數(shù)就不能調(diào)用它,只能通過manager結(jié)構(gòu)體來調(diào)用。是不是感覺有點(diǎn)封裝的意味。

void?init_manager(struct?manager*?manager_ptr)
{
????manager_ptr->operation1?=?operation1;
????manager_ptr->operation2?=?operation2;
????manager_ptr->data1?=?0;
????manager_ptr->data2?=?0;
}

去初始化函數(shù)我就不寫了。

如果operation函數(shù)在外面的文件定義,則可以作為init_manager函數(shù)的參數(shù)傳入,這種場景也非常常見。我實(shí)現(xiàn)了模塊A,該模塊的operation1函數(shù)處理數(shù)據(jù)并輸出一些結(jié)果。但是我并不知道使用該模塊的人想要什么格式的結(jié)果,比如有一些人想要json格式的結(jié)果,有些人想要xml格式的結(jié)果。我不能幫他們一一實(shí)現(xiàn)一個(gè)方法,我干脆叫你們統(tǒng)一按照我指定的函數(shù)模板,實(shí)現(xiàn)一個(gè)處理函數(shù),完了你們調(diào)用結(jié)構(gòu)體初始化函數(shù)注冊下,我會(huì)在operation1函數(shù)處理完數(shù)據(jù)后,調(diào)用你們的處理函數(shù),給你們一個(gè)滿意的結(jié)果。

為了達(dá)到上面的目的,簡單修改下,我們把函數(shù)operation2定義成一種類型,

typedef?int??(*FUN_CBK)(struct?manager *manager_ptr);

結(jié)構(gòu)體定義稍作修改:

struct?manager{
????int?data1;
????int?data2;
????int?(*operation1)(struct?manager*);
????FUN_CBK?call_back;
};

結(jié)構(gòu)體初始化函數(shù)也要做相應(yīng)的修改,增加了一個(gè)函數(shù)指針形參:

void?init_manager(struct?manager*?manager_ptr,?\
FUN_CBK?fun)
{
????manager_ptr->operation1?=?operation1;
????manager_ptr->call_back?=?fun;//用外部傳入的回調(diào)函數(shù)進(jìn)行初始化
????manager_ptr->data1?=?0;
????manager_ptr->data2?=?0;
}

通過上面的操作,我們用結(jié)構(gòu)體和函數(shù)指針完成了模塊化封裝。

我看了網(wǎng)上的博客,有些人為了特意模仿類,還用以下方式實(shí)現(xiàn)了類似于類的構(gòu)造函數(shù):

struct?manager?*manager_create(int?m,?int?n)
{
????struct?manager?*m?=?(struct?manager?*)\
????malloc(sizeof(struct?manager?*));
????m->data1?=?m;
????m->data2?=?n;
????m->operation1?=?operation1;
????m->operation2?=?operation2;
}

以及類似于類的析構(gòu)函數(shù):

void?manager_delete(struct?manager?*m_ptr)
{
????free(m_ptr);
????m_ptr?=?NULL;
}

使用示例:

struct?manager?*m_ptr?=?manager_create?(1,2);
manager_delete(m_ptr);

個(gè)人不是很喜歡這種做法,萬一忘記調(diào)用manager_delete還有內(nèi)存泄露的風(fēng)險(xiǎn)。

結(jié)構(gòu)體歸根到底還是結(jié)構(gòu)體,不能實(shí)現(xiàn)成員對外不可見。而C++中將成員聲明成private之后,外部就無法訪問了。C語言里想這么做,只能將該成員移出結(jié)構(gòu)體,定義為static形式。因?yàn)镃不支持在結(jié)構(gòu)體內(nèi)部定義static變量(不信,你可以自己去試下)。

為何不能在結(jié)構(gòu)體內(nèi)定義static變量,想想就知道了,static變量的地址在編譯鏈接之后是唯一且確定的,而結(jié)構(gòu)體只有在實(shí)例化時(shí)才能確定其地址,并且每個(gè)結(jié)構(gòu)體實(shí)例都有自己的地址空間。

3、多態(tài)

多態(tài)在上面的例子也有體現(xiàn)。C語言實(shí)現(xiàn)的多態(tài)并非是嚴(yán)格意義上的多態(tài),但是這種思想的應(yīng)用很廣泛,我們姑且叫它多態(tài)吧。你不解C++的多態(tài)也沒關(guān)系,絲毫不影響你理解下文。

linux的VFS便借鑒了這種思想。VFS(Virtual File System)是內(nèi)核提供的文件系統(tǒng)抽象層,其提供了文件系統(tǒng)的操作接口,可以隱藏底層不同文件系統(tǒng)的實(shí)現(xiàn)。

一個(gè)文件系統(tǒng)無非就是實(shí)現(xiàn)對文件、目錄的管理。針對文件VFS定義了統(tǒng)一的結(jié)構(gòu)體:

struct?file?{
????union?{
????????struct?llist_nodefu_llist;
????????struct?rcu_head?fu_rcuhead;
????}?f_u;
????struct?pathf_path;
????struct?inode*f_inode;/*?cached?value?*/
????const?struct?file_operations*f_op;
????……
};?

strcut file代表一個(gè)文件,每種文件系統(tǒng)(比如ext3,vfat)實(shí)現(xiàn)讀寫等操作的方式都不一樣,所以將這些方法封裝成函數(shù)指針,統(tǒng)一定義在結(jié)構(gòu)體struct file_operations內(nèi)。

struct?file_operations?{
????struct?module?*owner;
????loff_t?(*llseek)?(struct?file?*,?loff_t,?int);
????ssize_t?(*read)?(struct?file?*,?char?__user?*,?size_t,?loff_t?*);
????ssize_t?(*write)?(struct?file?*,?const?char?__user?*,?size_t,?loff_t?*);
????……
};

每個(gè)文件系統(tǒng)各自完成自己的實(shí)現(xiàn)。


再寫一個(gè)實(shí)際的例子。
定義一個(gè)人的標(biāo)準(zhǔn)接口和數(shù)據(jù)如下:

strcut?man{
????int?head;
????int?body;
????……
????void?(*say_hello)(void);//見面問候的方式
};

中國人見面時(shí),說你好:

void?china_say_hello(void)
{
????printf(“你好”);
}

英國人見面時(shí),說hello:

void?english_say_hello(void)
{
????printf(“hello”);
}

現(xiàn)在來初始化它們各自的問候方式:

struct?man?china{
????.say_hello?=?china_say_hello;
}
struct?man?english{
????.say_hello?=?English_say_hello;
}

英國人和中國人對外呈現(xiàn)都是struct man,其見面問候的接口都是man.say_hello,但其底層實(shí)現(xiàn)卻可以不一樣。

并且我們可以在程序運(yùn)行時(shí),隨意的更改中國人的問候方式。比如嬰兒時(shí)期,只會(huì)“哇哇”叫,長大了才會(huì)說“你好”,我們可以改變成員say_hello的值,讓其在不同時(shí)期指向不同的函數(shù),從而達(dá)到運(yùn)行時(shí)多態(tài)的目的。

其實(shí)呢,C++的多態(tài),也是通過函數(shù)指針來實(shí)現(xiàn)的,學(xué)習(xí)過C++的同學(xué)就會(huì)知道,含有虛函數(shù)的類,會(huì)維護(hù)一個(gè)虛函數(shù)表,里面存放了虛函數(shù)的地址。所以說啊,C語言是C++的母語,萬變不離指針,指針是C語言的一大法寶。


-END-


本文授權(quán)轉(zhuǎn)載自二進(jìn)制人生,作者:二進(jìn)制人生




推薦閱讀



【01】長見識:你真的知道C語言里extern "C" 的作用嗎?
【02】硬件工程師必知的10個(gè)C語言技巧
【03】C語言如何實(shí)現(xiàn)拷貝圖片?幾行代碼即可搞定
【04】C語言常用的一些轉(zhuǎn)換工具函數(shù)!
【05】2020年8月程序員工資最新統(tǒng)計(jì)


免責(zé)聲明:整理文章為傳播相關(guān)技術(shù),版權(quán)歸原作者所有,如有侵權(quán),請聯(lián)系刪除

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢抑制與過流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉