最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言也有封裝,繼承和多態(tài)你知道嗎

 更新時(shí)間:2022年03月22日 09:05:29   作者:半夏(????????)??????  
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言封裝,繼承,多態(tài),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助

我們知道封裝、繼承、多態(tài)是面向?qū)ο蟮娜筇匦裕覀円仓繡語(yǔ)言是面向過程的語(yǔ)言,那么可不可以在面向過程的語(yǔ)言中用面向?qū)ο蟮乃枷刖幊棠亍,F(xiàn)在我們就一起看看用C語(yǔ)言如何實(shí)現(xiàn)封裝、繼承、多態(tài)。

封裝

所謂封裝就是把實(shí)現(xiàn)的細(xì)節(jié)隱藏起來(lái),外部只能通過相關(guān)的函數(shù)對(duì)一個(gè)類進(jìn)行操作,一呢是方便代碼的復(fù)用,二也可以有效的保證代碼的安全性。那么我們看看Redis源碼中對(duì)于雙向鏈表的一個(gè)設(shè)計(jì)和實(shí)現(xiàn),是不是就是傳說中的封裝呢?

typedef struct listNode {
	struct listNode* prev;
	struct listNode* next;
	void* value;
} listNode;
 list* listCreate() {
	struct list* list;
	list = malloc(sizeof(struct list));
	if (list == NULL) return NULL;
 	list->head = list->tail = NULL;
	list->len = 0;
	return list;
}

繼承

繼承也是為了代碼的重用設(shè)計(jì)的,比如多個(gè)子類都有一些共同的屬性和方法,那么就可以將這些共同點(diǎn)抽象成一個(gè)父類,讓子類去繼承他,子類也就擁有了父類的特性,更好的實(shí)現(xiàn)了代碼的重用性。但是繼承也有很多缺點(diǎn),比如:

1.java中不能多繼承

2.如果繼承了一個(gè)類,那么就繼承了這個(gè)類的所有public的屬性和方法,即使你不想繼承

3.如果有一天父類的邏輯做了修改,那么子類的邏輯也被迫做了修改

基于這些原因呢,很多時(shí)候是不建議使用繼承的,而是優(yōu)先用組合的方式來(lái)達(dá)到代碼的復(fù)用。在Go語(yǔ)言中也沒有extends關(guān)鍵字,也是通過組合實(shí)現(xiàn)代碼的復(fù)用。那么在C語(yǔ)言中,雖然沒有繼承,但是我們可以組合啊,實(shí)現(xiàn)的效果是大同小異的。例如:

struct Shape {
    int area;
    Shape* crateShape();
};
 struct Rectangle {
    struct Shape shape;
    int width;
    int height;
};
 struct Square {
    struct Shape shape;
    int side;
};

多態(tài)

函數(shù)的指針

這里要回顧一下C語(yǔ)言基礎(chǔ)語(yǔ)法了,先來(lái)看看C語(yǔ)言中關(guān)于函數(shù)的指針。如果我們?cè)贑語(yǔ)言中定義了一個(gè)函數(shù),那么在編譯的時(shí)候會(huì)把函數(shù)的源代碼編譯成可執(zhí)行的的指令,然后分配一塊內(nèi)存去存放。這段空間的的地址就是函數(shù)的入口地址,每次調(diào)用的時(shí)候會(huì)從該地址入口開始執(zhí)行,函數(shù)名就代表了這個(gè)地址,因此函數(shù)名就是函數(shù)的指針。

那么我們就可以定義一個(gè)用來(lái)指向函數(shù)的指針變量,用來(lái)存放某一函數(shù)的入口地址。例如:int (* add) (int, int)。這行代碼中第一個(gè)int表示的是返回值類型;(* add)表示add是一個(gè)指針變量,括號(hào)不能省略;后面的(int, int)表示參數(shù)類型是兩個(gè)int類型,括號(hào)不能省略,括號(hào)表示指針變量不是指向其他類型的,而是函數(shù)類型的。之前對(duì)函數(shù)的調(diào)用都是通過函數(shù)名,那么現(xiàn)在有了指針變量,我們也可以通過指針變量來(lái)對(duì)函數(shù)進(jìn)行調(diào)用。

int main() {
    // 通過函數(shù)名調(diào)用
    max(9, 2);
     // 通過函數(shù)的指針變量調(diào)用
    int (*p)(int, int);
	// 將函數(shù)max的入口地址賦值給指針變量p
    p = max();
    (*p)(a, b)
}
 int add(int x, int y) {
    return x + y;
}

通過函數(shù)的指針實(shí)現(xiàn)多態(tài)

我們看下面代碼,ShapeVtbl這個(gè)結(jié)構(gòu)體中定義了一個(gè)計(jì)算面積的函數(shù),沒有實(shí)現(xiàn),我們叫做虛函數(shù)表。Shape這個(gè)結(jié)構(gòu)體中定義了兩個(gè)屬性,一個(gè)vtbl,一個(gè)area。

struct Shape {
    struct ShapeVtbl *vtbl;
    int area;
};
 struct ShapeVtbl {
    float (*area)(struct Shape* self);
};
 struct Rectangle {
    struct Shape shape;
    int width;
    int height;
};
 struct Square {
    struct Shape shape;
    int side;
};

這里我們分別定義了計(jì)算矩形面積的方法rectangle_area和計(jì)算正方形面積的方法square_area。也初始化了兩個(gè)ShapeVtbl,讓他們的函數(shù)指針分別指向不同的函數(shù)入口。那么在實(shí)際運(yùn)行的時(shí)候代碼就會(huì)根據(jù)我們的選擇調(diào)用不同的函數(shù),呈現(xiàn)出多態(tài)的效果。

// 計(jì)算矩形面積的方法
float rectangle_area(struct Shape *self) {
    struct Rectangle *r = (struct Rectangle *)self;
    self->area = r->width * r->height;
    return self->area;
}
 // 計(jì)算正方形面積的方法
float square_area(struct Shape *self) {
    struct Square *r = (struct Square *)self;
    self->area = r->side * r->side;
    return self->area;
}
 // 初始化了兩個(gè)ShapeVtbl,讓area函數(shù)分別指向了rectangle_area、square_area
struct ShapeVtbl vtbl1 = {
    rectangle_area,
};
 struct ShapeVtbl vtbl2 = {
    square_area,
};
 // 計(jì)算面積的方法,這里的area函數(shù)的邏輯是在運(yùn)行時(shí)期動(dòng)態(tài)綁定的,也就是有self中函數(shù)指針指向的實(shí)際函數(shù)決定的
float shape_area(struct Shape *self) {
    struct ShapeVtbl *v = self->vtbl;
    return v->area(self);
}
 struct Square* createSquare() {
    struct Square *s = malloc(sizeof(struct Square));
    s->side = 5;
    s->shape.vtbl = &vtbl2;
}
 int main() {
    struct Square* s = createSquare();
    printf("area => %f\n", shape_area((struct Shape *)s));
}

更多可以參考圖例:

在這里插入圖片描述

這樣的設(shè)計(jì)在redis源碼中有很多應(yīng)用,比如redis中的字典,dict結(jié)構(gòu)體定義了字典的基本屬性以及屬于dict的一些特定函數(shù),代碼在dict.h中。

/*
 * 字典類型特定函數(shù),定義了計(jì)算哈希值、復(fù)制鍵、比較鍵等函數(shù)
 */
typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
 } dictType;
 /*
 * 字典
 */
typedef struct dict {
     // 類型特定函數(shù)
    dictType *type;
     void *privdata;
     dictht ht[2];
     int rehashidx;
     int iterators;
 } dict;

而在redis中,dict的應(yīng)用比較多,鍵的類型也可能有sds、redisObject等多種類型,他們的鍵比較函數(shù),hash函數(shù)等都是不同的,因此有了下面的代碼,分別定義了適應(yīng)于各種鍵的對(duì)比、hash等函數(shù),并封裝在了不同的dictType,代碼在redis.c中。那么在實(shí)際應(yīng)用中,只需要為不同的類型選擇不同的dictType即可。

dictType clusterNodesBlackListDictType = {
    dictSdsCaseHash,            /* hash function */
    NULL,                       /* key dup */
    NULL,                       /* val dup */
    dictSdsKeyCaseCompare,      /* key compare */
    dictSdsDestructor,          /* key destructor */
    NULL                        /* val destructor */
};
 /* Migrate cache dict type. */
dictType migrateCacheDictType = {
    dictSdsHash,                /* hash function */
    NULL,                       /* key dup */
    NULL,                       /* val dup */
    dictSdsKeyCompare,          /* key compare */
    dictSdsDestructor,          /* key destructor */
    NULL                        /* val destructor */
};
 /* Replication cached script dict (server.repl_scriptcache_dict).
 * Keys are sds SHA1 strings, while values are not used at all in the current
 * implementation. */
dictType replScriptCacheDictType = {
    dictSdsCaseHash,            /* hash function */
    NULL,                       /* key dup */
    NULL,                       /* val dup */
    dictSdsKeyCaseCompare,      /* key compare */
    dictSdsDestructor,          /* key destructor */
    NULL                        /* val destructor */
};
 int dictSdsKeyCompare(void *privdata, const void *key1,
        const void *key2)
{
    int l1,l2;
    DICT_NOTUSED(privdata);
     l1 = sdslen((sds)key1);
    l2 = sdslen((sds)key2);
    if (l1 != l2) return 0;
    return memcmp(key1, key2, l1) == 0;
}

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容! 

相關(guān)文章

  • C++17中的折疊表達(dá)式實(shí)現(xiàn)

    C++17中的折疊表達(dá)式實(shí)現(xiàn)

    這篇文章主要介紹了C++17中的折疊表達(dá)式實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • C++調(diào)用python(執(zhí)行py文件)的全過程

    C++調(diào)用python(執(zhí)行py文件)的全過程

    這篇文章主要給大家介紹了關(guān)于C++調(diào)用python(執(zhí)行py文件)的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12
  • C++基于socket編程實(shí)現(xiàn)聊天室功能

    C++基于socket編程實(shí)現(xiàn)聊天室功能

    這篇文章主要介紹了C++基于socket編程實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • VScode配置cuda開發(fā)環(huán)境的實(shí)現(xiàn)步驟

    VScode配置cuda開發(fā)環(huán)境的實(shí)現(xiàn)步驟

    本文主要介紹了VScode配置cuda開發(fā)環(huán)境的實(shí)現(xiàn)步驟,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • 詳解C++中const_cast與reinterpret_cast運(yùn)算符的用法

    詳解C++中const_cast與reinterpret_cast運(yùn)算符的用法

    這篇文章主要介紹了C++中const_cast與reinterpret_cast運(yùn)算符的用法,經(jīng)常被用于表達(dá)式中的類型轉(zhuǎn)換,需要的朋友可以參考下
    2016-01-01
  • vscode編譯運(yùn)行c語(yǔ)言報(bào)錯(cuò)亂碼的解決

    vscode編譯運(yùn)行c語(yǔ)言報(bào)錯(cuò)亂碼的解決

    本文主要介紹了vscode編譯運(yùn)行c語(yǔ)言報(bào)錯(cuò)亂碼,文中通過圖文介紹的的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • 詳解C/C++實(shí)現(xiàn)各種字符轉(zhuǎn)換方法合集

    詳解C/C++實(shí)現(xiàn)各種字符轉(zhuǎn)換方法合集

    這篇文章主要為大家詳細(xì)介紹了C/C++中實(shí)現(xiàn)各種字符轉(zhuǎn)換的方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++具有一定借鑒價(jià)值,需要的可以參考一下
    2022-09-09
  • char str[] 與 char *str的區(qū)別詳細(xì)解析

    char str[] 與 char *str的區(qū)別詳細(xì)解析

    以下是對(duì)char str[]與char *str的區(qū)別進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來(lái)參考下
    2013-09-09
  • c++11中regex正則表達(dá)式示例簡(jiǎn)述

    c++11中regex正則表達(dá)式示例簡(jiǎn)述

    這篇文章主要給大家介紹了關(guān)于c++11中regex正則表達(dá)式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用c++11具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • C語(yǔ)言實(shí)現(xiàn)停車場(chǎng)管理

    C語(yǔ)言實(shí)現(xiàn)停車場(chǎng)管理

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言課程設(shè)計(jì)之停車場(chǎng)管理問題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評(píng)論

香河县| 奇台县| 宁陵县| 肥城市| 新干县| 赣州市| 宜兰县| 陇西县| 呈贡县| 萝北县| 台中市| 益阳市| 涟水县| 河津市| 大名县| 禄丰县| 监利县| 简阳市| 诸城市| 庐江县| 武威市| 修文县| 东乡县| 休宁县| 安化县| 彩票| 大英县| 沁阳市| 读书| 荆门市| 千阳县| 岢岚县| 胶南市| 黄山市| 崇义县| 修武县| 天水市| 柳林县| 东海县| 平谷区| 五峰|