楊韜
(廣州致遠(yuǎn)電子股份有限公司,廣東 廣州 510660)
摘要:多年以來(lái),C語(yǔ)言在嵌入式軟件開(kāi)發(fā)中被廣泛使用,但由于開(kāi)發(fā)人員和應(yīng)用場(chǎng)景等原因,面向?qū)ο?/a>、設(shè)計(jì)模式等優(yōu)秀的軟件開(kāi)發(fā)方法始終沒(méi)有很好地運(yùn)用起來(lái)。時(shí)至今日,物聯(lián)網(wǎng)等應(yīng)用的興起,給嵌入式軟件開(kāi)發(fā)帶來(lái)新的挑戰(zhàn),而傳統(tǒng)的面向過(guò)程開(kāi)發(fā)已經(jīng)難以支撐這些復(fù)雜的應(yīng)用。因此,有必要在嵌入式軟件開(kāi)發(fā)中引入面向?qū)ο蟆⒃O(shè)計(jì)模式等優(yōu)秀的軟件開(kāi)發(fā)方法。面向?qū)ο笫乾F(xiàn)代軟件方法的根基,面向?qū)ο篌w現(xiàn)在類(lèi)上,使用類(lèi)來(lái)創(chuàng)建對(duì)象的過(guò)程就是實(shí)例化。文章結(jié)合C語(yǔ)言的特性,對(duì)使用C語(yǔ)言實(shí)現(xiàn)類(lèi)實(shí)例化進(jìn)行了討論。
關(guān)鍵詞: C語(yǔ)言;面向?qū)ο螅活?lèi);實(shí)例化
中圖分類(lèi)號(hào):TP312文獻(xiàn)標(biāo)識(shí)碼:ADOI:10.19358/j.issn.16747720.2016.23.004
引用格式:楊韜. 用C語(yǔ)言實(shí)現(xiàn)類(lèi)實(shí)例化的研究[J].微型機(jī)與應(yīng)用,2016,35(23):15-17.
0引言
物聯(lián)網(wǎng)等應(yīng)用的興起,給嵌入式軟件開(kāi)發(fā)帶來(lái)新的挑戰(zhàn),而傳統(tǒng)的面向過(guò)程開(kāi)發(fā)已經(jīng)難以支撐這些復(fù)雜的應(yīng)用。因此,有必要在嵌入式軟件開(kāi)發(fā)中引入面向?qū)ο蟆⒃O(shè)計(jì)模式等優(yōu)秀的軟件開(kāi)發(fā)方法。本文討論了如何使用C語(yǔ)言來(lái)實(shí)現(xiàn)類(lèi)的實(shí)例化。在C++等面向?qū)ο笳Z(yǔ)言中對(duì)類(lèi)做了原生的支持,使用new這類(lèi)關(guān)鍵字即可實(shí)例化一個(gè)對(duì)象。盡管C語(yǔ)言并不支持new,但是通過(guò)對(duì)實(shí)例化過(guò)程的分析和拆分,也能實(shí)現(xiàn)實(shí)例化。
1基本概念[1]
1.1類(lèi)
面向?qū)ο笥蟹庋b、繼承、多態(tài)三大特性,這些特性主要通過(guò)類(lèi)來(lái)體現(xiàn)。類(lèi)就是一個(gè)封裝了屬性以及相關(guān)操作的代碼的邏輯實(shí)體。
類(lèi)具有屬性,它是對(duì)象的狀態(tài)的抽象,用數(shù)據(jù)結(jié)構(gòu)來(lái)描述類(lèi)的屬性。
類(lèi)具有方法,它是對(duì)象的行為的抽象,用方法名和實(shí)現(xiàn)該操作的方法來(lái)描述。
除了封裝屬性和操作外,類(lèi)還具有訪問(wèn)控制的能力,比如,某些屬性和方法可以是私有的,不能被外界訪問(wèn)。通過(guò)訪問(wèn)控制,能夠?qū)?nèi)部數(shù)據(jù)提供不同級(jí)別的保護(hù),以防止外界意外地改變或使用了私有部分。不同的編程語(yǔ)言提供的訪問(wèn)控制等級(jí)不盡相同,但都有公有、私有兩個(gè)等級(jí)。
類(lèi)是抽象的數(shù)據(jù)類(lèi)型,在內(nèi)存中并不存在(Python等動(dòng)態(tài)語(yǔ)言除外),只有類(lèi)的實(shí)例存在于內(nèi)存中。
1.2對(duì)象
對(duì)象是人們要進(jìn)行研究的任何事物,從最簡(jiǎn)單的整數(shù)到復(fù)雜的飛機(jī)等均可看作為對(duì)象,它不僅能表示具體的事物,還能表示抽象的規(guī)則、計(jì)劃或事件。
對(duì)象具有狀態(tài),一個(gè)對(duì)象用數(shù)據(jù)值來(lái)描述它的狀態(tài)。
對(duì)象還有操作,用于改變對(duì)象的狀態(tài),對(duì)象及其操作就是對(duì)象的行為。
對(duì)象實(shí)現(xiàn)了數(shù)據(jù)和操作的結(jié)合,使數(shù)據(jù)和操作封裝于對(duì)象的統(tǒng)一體中。
1.3實(shí)例化
用類(lèi)創(chuàng)建對(duì)象的過(guò)程就是實(shí)例化,創(chuàng)建的對(duì)象被稱(chēng)為類(lèi)的實(shí)例。實(shí)例化包含兩個(gè)步驟,第一步是分配對(duì)象的內(nèi)存,第二步是初始化對(duì)象的內(nèi)存。
2類(lèi)封裝的C語(yǔ)言實(shí)現(xiàn)
類(lèi)的第一大特性為封裝,封裝即將對(duì)象的屬性和方法封裝在一起,在C語(yǔ)言中可以使用.C、.H和結(jié)構(gòu)體實(shí)現(xiàn)類(lèi)的封裝特性。
以圖1中Human類(lèi)為例,可以使用human.h、human.c、struct human三個(gè)元素來(lái)完成封裝,human.c為human.h中函數(shù)聲明的實(shí)現(xiàn),本文不討論這些細(xì)節(jié),所以只給出如下human.h的關(guān)鍵代碼片段:
typedef struct human {
const char *name;
int_money;
} human_t;
human_t *human_init (human_t *p_this, const char *name, int money);
voidhuman_talk (human_t *p_this, const char *p_words);
voidhuman_buy (human_t *p_this, const char *p_something, unsigned price, unsigned count);
voidhuman_deinit (human_t *p_this);
3類(lèi)實(shí)例化的C語(yǔ)言實(shí)現(xiàn)
實(shí)例化包含兩個(gè)步驟:分配對(duì)象的內(nèi)存和初始化對(duì)象的內(nèi)存。接下來(lái)本文以圖1中Human類(lèi)的實(shí)例化為例,討論C語(yǔ)言如何實(shí)現(xiàn)類(lèi)的實(shí)例化。
3.1對(duì)象的內(nèi)存
如果把類(lèi)看做類(lèi)型,那么類(lèi)的實(shí)例就是變量,既然是變量,那么就有動(dòng)態(tài)變量、靜態(tài)變量和棧變量之分。在C語(yǔ)言中,使用malloc()這類(lèi)動(dòng)態(tài)內(nèi)存分配函數(shù)得到的變量就是動(dòng)態(tài)變量;全局變量和加了static關(guān)鍵字的變量就是靜態(tài)變量;在函數(shù)內(nèi)創(chuàng)建的局部變量就是棧變量。下面的代碼展示了C語(yǔ)言中的這幾類(lèi)變量:
#include "human.h"
struct humang_john;/* 靜態(tài)變量 */
static struct human __g_john;/* 靜態(tài)變量 */
void foo (void)
{
static struct human s_john;/* 靜態(tài)變量 */
struct human john;/* 棧變量 */
struct human*p_john = malloc(sizeof(*p_john));
/* 動(dòng)態(tài)變量 */
}
站在內(nèi)存的角度,可以把類(lèi)看做結(jié)構(gòu)體類(lèi)型,類(lèi)的實(shí)例就是結(jié)構(gòu)體變量,因此,對(duì)象也就有動(dòng)態(tài)對(duì)象、靜態(tài)對(duì)象和棧對(duì)象之分,它們之間的區(qū)別如表1所示。
free()
釋放內(nèi)存內(nèi)存分配可能失敗,花費(fèi)的時(shí)間可能不確定;需要處理內(nèi)存分配失敗的情況,增加程序的復(fù)雜性可以在需要時(shí)創(chuàng)建和銷(xiāo)毀對(duì)象靜態(tài)對(duì)象位于.data、
.bss內(nèi)存段需要編譯時(shí)確定對(duì)象的數(shù)量;一直占用內(nèi)存;對(duì)象數(shù)量太多太大時(shí)會(huì)影響程序啟動(dòng)時(shí)間確定性好,只要程序能夠運(yùn)行起來(lái),就一定能夠創(chuàng)建成功棧對(duì)象位于系統(tǒng)
棧、對(duì)象棧對(duì)象太大會(huì)導(dǎo)致棧溢出自動(dòng)完成對(duì)象內(nèi)存的分配和回收
對(duì)于嵌入式軟件中的C面向?qū)ο缶幊蹋浞掷斫獗?中的這三類(lèi)對(duì)象是非常有必要的。大多數(shù)情況下,一個(gè)類(lèi)都要能夠被實(shí)例化為靜態(tài)對(duì)象。
3.2對(duì)象的初始化
初始化對(duì)象就是初始化對(duì)象的內(nèi)存,在初始化之前,必然要先得到對(duì)象的內(nèi)存(上一小節(jié)已討論),但無(wú)論對(duì)象的內(nèi)存是何種類(lèi)型,初始化的操作都是相同的。在JAVA等編程語(yǔ)言中,完成此操作的函數(shù)被稱(chēng)作構(gòu)造函數(shù),使用C語(yǔ)言來(lái)實(shí)現(xiàn)就是一個(gè)名為xxxx_init()的初始化函數(shù),也可稱(chēng)之為構(gòu)造函數(shù)。
以Human類(lèi)為例,它的初始化函數(shù)human_init()如下面的代碼所示,可留意到對(duì)象的內(nèi)存需要顯式傳遞給它。
human_t *human_init (human_t *p_this, const char *name, int money)
{
p_this->name = name;
p_this->_money = money;
return p_this;
}
3.3實(shí)例化
前面兩小節(jié)分別討論了對(duì)象的內(nèi)存和對(duì)象的初始化,這兩步組成了實(shí)例化。下面的代碼展示了不同類(lèi)型對(duì)象的實(shí)例化:
#include "human.h"
human_tg_john;/* 靜態(tài)對(duì)象 */
statichuman_t__g_jen;/* 靜態(tài)對(duì)象 */
void foo (void)
{
static human_ts_jack;/* 靜態(tài)對(duì)象 */
human_t tom;/* 棧對(duì)象 */
human_t*p_lee_mem= malloc(sizeof(*p_lee_mem));
/* 動(dòng)態(tài)對(duì)象 */
// 實(shí)例化上面定義的靜態(tài)對(duì)象、動(dòng)態(tài)對(duì)象和棧對(duì)象
human_t *p_john= human_init(&g_john, "john", 100);
human_t *p_jen = human_init(&__g_jen, "jen", 100);
human_t *p_jack = human_init(&s_jack, "jack", 100);
human_t *p_tom = human_init(&tom, "tom", 100);
human_t *p_lee = human_init(p_lee_mem, "lee", 100);
3.4訪問(wèn)對(duì)象
對(duì)象實(shí)例化后便存于內(nèi)存中,此時(shí)可以訪問(wèn)對(duì)象的屬性和方法,下面的代碼展示了對(duì)象的訪問(wèn):
#include "human.h"
void foo (void)
{
human_t john;/* 定義對(duì)象內(nèi)存 */
p_john = human_init(&jhon, "John", 100);
/* 初始化對(duì)象 */
printf("Human %s is born!", p_john->name);
/* 訪問(wèn)對(duì)象的屬性 */
human_talk(p_john, "I am hungry");
/* 訪問(wèn)對(duì)象的方法 */
human_deinit(&john)/* 對(duì)象解初始化 */
}
3.5銷(xiāo)毀對(duì)象
當(dāng)對(duì)象不再使用時(shí),便可銷(xiāo)毀之。銷(xiāo)毀對(duì)象與創(chuàng)建對(duì)象(實(shí)例化)的操作相反,首先對(duì)對(duì)象進(jìn)行解初始化操作,然后再釋放對(duì)象的內(nèi)存。
以Human類(lèi)為例,首先調(diào)用human_deinit()完成對(duì)象的解初始化,接下來(lái),如果是靜態(tài)對(duì)象或棧對(duì)象就不用顯式釋放對(duì)象的內(nèi)存,因?yàn)殪o態(tài)對(duì)象或棧對(duì)象有確定的生命周期;如果是調(diào)用malloc()等函數(shù)得到了動(dòng)態(tài)對(duì)象,則必須調(diào)用free()等對(duì)應(yīng)的函數(shù)釋放對(duì)象的內(nèi)存。下面的代碼展示了各種對(duì)象的銷(xiāo)毀:
#include "human.h"
human_tg_john;/* 靜態(tài)對(duì)象 */
statichuman_t__g_jen;/* 靜態(tài)對(duì)象 */
void foo (void)
{
static human_ts_jack;/* 靜態(tài)對(duì)象 */
human_t tom;/* 棧對(duì)象 */
human_t*p_lee_mem= malloc(sizeof(*p_lee_mem));
/* 動(dòng)態(tài)對(duì)象 */
// 實(shí)例化上面定義的靜態(tài)對(duì)象、動(dòng)態(tài)對(duì)象和棧對(duì)象
human_t *p_john = human_init(&g_john, "john", 100);
human_t *p_jen = human_init(&__g_jen, "jen", 100);
human_t *p_jack = human_init(&s_jack, "jack", 100);
human_t *p_tom = human_init(&tom, "tom", 100);
human_t *p_lee = human_init(p_lee_mem, "lee", 100);
/* 銷(xiāo)毀對(duì)象 */
human_deinit(p_john);
human_deinit(p_jen);
human_deinit(p_jack);
human_deinit(p_tom);
human_deinit(p_lee);
free(p_lee_mem);
/* 注意:需要用戶(hù)釋放動(dòng)態(tài)申請(qǐng)的對(duì)象內(nèi)存 */
}
4結(jié)論
本文通過(guò)使用C語(yǔ)言實(shí)現(xiàn)Human類(lèi)的實(shí)例化,討論了如何使用C語(yǔ)言來(lái)實(shí)現(xiàn)類(lèi)的實(shí)例化。在C++等面向?qū)ο笳Z(yǔ)言中對(duì)類(lèi)做了原生的支持,使用new這類(lèi)關(guān)鍵字即可實(shí)例化一個(gè)對(duì)象。盡管C語(yǔ)言并不支持new,但是通過(guò)對(duì)實(shí)例化過(guò)程的分析和拆分,也能實(shí)現(xiàn)實(shí)例化。
參考文獻(xiàn)
[1] 百度. 百度百科/面向?qū)ο螅跡B/OL].(2016-08-08).http://baike.baidu.com/link?url=6XlXEOSlrKn87S7SJv4 UWSX7EjstoDVm wJ13OAod XUrUrnZkVg3ntPFir Ey5c6mqOb ZZOevQI6K3Ungq1Mq.