色yeye在线视频观看_亚洲人亚洲精品成人网站_一级毛片免费播放_91精品一区二区中文字幕_一区二区三区日本视频_成人性生交大免费看

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > C語言實現類繼承多態封裝

C語言實現類繼承多態封裝 時間:2018-09-26      來源:未知

學習嵌入式,C語言是必須學習的一門語言,C語言在設計之初是為了提供一種能以簡易的方式編譯、處理低級存儲器、產生少量的機器碼以及不需要任何運行環境支持便能運行的編程語言。C語言不光提供了許多低級處理的功能,而且保持著良好跨平臺的特性,以一個標準規格寫出的C語言程序可在許多電腦平臺上進行編譯,甚至包含一些嵌入式處理器(單片機或稱MCU)以及超級電腦等作業平臺。

掌握了C語言,其他的語言也會很容易上手,一些面向對象的語言比如:C++、JAVA等都會很輕松的上手。

我們都知道面向對象的三大基本特征:封裝、繼承和多態,C++語言和編譯器都對這些特征有著強有力的支持,但是對于C這樣的函數式語言,如何實現面向對象?引用一句話:面向對象從來都是思想,而不是語言! 理解面向對象的編程思想,我們使用C語言這樣的較低級的語言也同樣可以實現OOP,里面具體用到的有C語言中的宏,結構體,函數指針, 聚合組合等知識。在C中有許多技巧可以實現多態。

本文的目的是使用C語言實現繼承和多態。通過創建一個VTable(virtual table)和在基類和派生類對象之間提供正確的訪問,我們能在C中實現繼承和多態。VTable能通過維護一張函數表指針表來實現。為了提供基類和派生類對象之間的訪問,我們可以在基類中維護派生類的引用和在派生類中維護基類的引用。

在C中實現繼承和多態之前,首先我們看看知道類(Class)在C++中如何表示。

1、類在C中的表示

//Person.h

class Person

{

private:

char* pFirstName;

char* pLastName;

public:

Person(constchar* pFirstName, constchar* pLastName); //constructor

~Person(); //destructorvoid displayInfo();

void writeToFile(constchar* pFileName);

};

在C++中的創建一個類"Person"。

用C語言來表示上面的類,我們可以使用結構體,并用操作結構體的函數表示成員函數。

//Person.h

typedef struct _Person

{

char* pFirstName;

char* pLastName;

}Person;

void new_Person(const char* const pFirstName, const char* const pLastName); //constructor

void delete_Person(Person* const pPersonObj); //destructor

void Person_DisplayInfo(Person* const pPersonObj);void Person_WriteToFile(Person* const pPersonObj, const char* const pFileName);

這里,定義的操作結構體Person的函數沒有封裝。為了實現封裝,即綁定數據、函數、函數指針。我們需要創建一個函數指針表。

構造函數new_Person()將設置函數指針值以指向合適的函數。這個函數指針表將作為對象訪問函數的接口。

2. 下面我們重新定義C中實現類Person。

//Person.h

typedef struct _Person Person;

//declaration of pointers to functions

typedef void (*fptrDisplayInfo)(Person*);typedef void (*fptrWriteToFile)( Person*, constchar*);typedef void (*fptrDelete)( Person *) ;

typedef struct _Person

{

char* pFName;

char* pLName;

//interface for function

fptrDisplayInfo Display;

fptrWriteToFile WriteToFile;

fptrDelete Delete;

}Person;

Person* new_Person(const char* const pFirstName,

const char* const pLastName); //constructor

void delete_Person(Person* const pPersonObj); //destructor

void Person_DisplayInfo(Person* const pPersonObj);void Person_WriteToFile(Person* const pPersonObj, const char* pFileName);

new_Person()函數作為構造函數,它返回新創建的結構體實例。它初始化函數指針接口去訪問其它成員函數。

這里要注意的一點是,我們僅僅定義了那些允許公共訪問的函數指針,并沒有給定私有函數的接口。

讓我們看一下new_Person()函數或C中類Person的構造函數。

//Person.c

person* new_Person(constchar* const pFirstName, constchar* const pLastName)

{

Person* pObj = NULL;

//allocating memory

pObj = (Person*)malloc(sizeof(Person));

if (pObj == NULL)

{

return NULL;

}

pObj->pFirstName = malloc(sizeof(char)*(strlen(pFirstName)+1));

if (pObj->pFirstName == NULL)

{

return NULL;

}

strcpy(pObj->pFirstName, pFirstName);

pObj->pLastName = malloc(sizeof(char)*(strlen(pLastName)+1));

if (pObj->pLastName == NULL)

{

return NULL;

}

strcpy(pObj->pLastName, pLastName);

//Initializing interface for access to functions

pObj->Delete = delete_Person;

pObj->Display = Person_DisplayInfo;

pObj->WriteToFile = Person_WriteToFile;

return pObj;

}

其他幾個方法的實現:

void delete_Person(Person* const pPersonObj)

{

printf("call Person_DisplayInfo()\n");

free(pPersonObj);

}

void Person_DisplayInfo(Person* const pPersonObj)

{

printf("call Person_DisplayInfo()\n");

printf("pFirstName:%s pLastName:%s\n",pPersonObj->pFirstName,pPersonObj->pLastName);

}

void Person_WriteToFile(Person* const pPersonObj, const char* pFileName)

{

printf("call Person_WriteToFile()\n");

}

創建完對象之后,我們能夠訪問它的數據成員和函數。

main()

{

Person* pPersonObj = new_Person("pengdan", "farsight");

pPersonObj->Display(pPersonObj);

pPersonObj->WriteToFile(pPersonObj, "persondata.txt");

pPersonObj->Delete(pPersonObj);

pPersonObj = NULL;

}

注意:不像C++,在C中我們不能在函數中直接訪問數據成員。在C++中,可以隱式通過“this”指針直接訪問數據成員。

我們知道C中是沒有“this”指針的,通過顯示地傳遞對象給成員函數。在C中為了訪問類的數據成員,

我們需要把調用對象作為函數參數傳遞。上面的例子中,我們把調用對象作為函數的第一個參數,通過這種方法,

函數可以訪問對象的數據成員。

3、在C中類的表現

Person類的表示——檢查初始化接口指向成員函數:

3.1、繼承和多態的簡單例子

繼承-Employee類繼承自Person類:

在上面的例子中,類Employee繼承類Person的屬性。因為DisplayInfo()和WriteToFile()函數是virtual的,

我們能夠從Person的實例訪問Employee對象中的同名函數。為了實現這個,我們創建Person實例的時候也初始化Employee類。

多態使這成為可能。 在多態的情況下,去解析函數調用,C++使用VTable——即一張函數指針表。

前面我們在結構體中維護的指向函數的指針接口的作用類似于VTable。

//Polymorphism in C++

Person PersonObj("pengdan", "farsight");

Employee EmployeeObj("kouxiaojuan", "liuyan", "HR", "TCS", 40000);

Person* ptrPersonObj = NULL;

//preson pointer pointing to person object

ptrPersonObj = &PersonObj;//displaying person info

ptrPersonObj ->Display();//writing person info in the persondata.txt file

ptrPersonObj ->WriteToFile("persondata.txt");

//preson pointer pointing to employee object

ptrPersonObj = &EmployeeObj;//displaying employee info

ptrPersonObj ->Display();//writing empolyee info in the employeedata.txt file

ptrPersonObj ->WriteToFile("employeedata.txt");

在C中,繼承可以通過在派生類對象中維護一個基類對象的引用來完成。在基類實例的幫助下,women可以訪問基類的數據成員和函數。然而,為了實現多態,基類對象應該能夠訪問派生類對象的數據。為了實現這個,基類應該有訪問派生類的數據成員的權限。

為了實現虛函數,派生類的函數簽名應該和基類的函數指針類似。即派生類函數將以基類對象的一個實例為參數。我們在基類中維護一個派生類的引用。在函數實現上,我們可以從派生類的引用訪問實際派生類的數據。

3.2、在C中結構體中的等效表示

C中的繼承-Person和Employee結構體:

如圖所示,我們在基類結構體中聲明了一個指針保存派生類對像,并在派生類結構體中聲明一個指針保存基類對象。

在基類對象中,函數指針指向自己的虛函數。在派生類對象的構造函數中,我們需要使基類的接口指向派生類的成員函數。這使我們可以通過基類對象(多態)靈活的調用派生類函數。更多細節,請檢查Person和Employee對象的構造函數。

當我們討論C++中的多態時,有一個對象銷毀的問題。為了正確的清楚對象,它使用虛析構函數。在C中,這可以通過使基類的刪除函數指針指向派生類的析構函數。派生類的析構函數清楚派生類的數據和基類的數據和對象。注意:檢查例子的源碼中,實現須構造函數和虛函數的實現細節。

//Person.h

typedef struct _Person Person;

//pointers to function

typedef void (*fptrDisplayInfo)(Person*);typedef void (*fptrWriteToFile)(Person*, const char*);typedef void (*fptrDelete)(Person*) ;

typedefstruct _person

{

void* pDerivedObj;

char* pFirstName;

char* pLastName;

fptrDisplayInfo Display;

fptrWriteToFile WriteToFile;

fptrDelete Delete;

}person;

Person* new_Person(constchar* const pFristName,

constchar* const pLastName); //constructor

void delete_Person(Person* const pPersonObj); //destructor

void Person_DisplayInfo(Person* const pPersonObj);void Person_WriteToFile(Person* const pPersonObj, constchar* const pFileName);

//Person.c//construction of Person object

Person* new_Person(constchar* const pFirstName, constchar* const pLastName)

{

Person* pObj = NULL;

//allocating memory

pObj = (Person*)malloc(sizeof(Person));

if (pObj == NULL)

{

return NULL;

}

//pointing to itself as we are creating base class object

pObj->pDerivedObj = pObj;

pObj->pFirstName = malloc(sizeof(char)*(strlen(pFirstName)+1));

if (pObj->pFirstName == NULL)

{

return NULL;

}

strcpy(pObj->pFirstName, pFirstName);

pObj->pLastName = malloc(sizeof(char)*(strlen(pLastName)+1));

if (pObj->pLastName == NULL)

{

return NULL;

}

strcpy(pObj->pLastName, pLastName);

//Initializing interface for access to functions//destructor pointing to destrutor of itself

pObj->Delete = delete_Person;

pObj->Display = Person_DisplayInfo;

pObj->WriteToFile = Person_WriteToFile;

return pObj;

}

創建Person對象

其他幾個方法的實現:

void delete_Person(Person* const pPersonObj)

{

printf("call Person_DisplayInfo()\n");

free(pPersonObj);

}

void Person_DisplayInfo(Person* const pPersonObj)

{

printf("call Person_DisplayInfo()\n");

printf("pFirstName:%s pLastName:%s\n",pPersonObj->pFirstName,pPersonObj->pLastName);

}

void Person_WriteToFile(Person* const pPersonObj, const char* pFileName)

{

printf("call Person_WriteToFile()\n");

}

Person對象的結構

創建Employee對象

//Employee.h

#include "Person.h"

typedef struct _Employee Employee;

typedefstruct _Employee

{

Person* pBaseObj;

char* pDepartment;

char* pCompany;

int nSalary;

//If there is any employee specific functions; add interface here.

}Employee;

Person* new_Employee(const char* const pFirstName, const char* const pLastName,

const char* const pDepartment, const char* const pCompany,

int nSalary); //constructor

void delete_Employee(Person* const pPersonObj); //destructor

void Employee_DisplayInfo(Person* const pPersonObj);void Employee_WriteToFile(Person* const pPersonObj, const char* const pFileName);

//Employee.c

Person* new_Employee(const char* const pFirstName, const char* const pLastName,

const char* const pDepartment,

const char* const pCompany, int nSalary)

{

Employee* pEmpObj;

//calling base class construtor

Person* pObj = new_Person(pFirstName, pLastName);

//allocating memory

pEmpObj = malloc(sizeof(Employee));

if (pEmpObj == NULL)

{

pObj->Delete(pObj);

return NULL;

}

pObj->pDerivedObj = pEmpObj;

pEmpObj->pDepartment = malloc(sizeof(char)*(strlen(pDepartment)+1));

if(pEmpObj->pDepartment == NULL)

{

return NULL;

}

strcpy(pEmpObj->pDepartment, pDepartment);

pEmpObj->pCompany = malloc(sizeof(char)*(strlen(pCompany)+1));

if(pEmpObj->pCompany== NULL)

{

return NULL;

}

strcpy(pEmpObj->pCompany, pCompany);

pEmpObj->nSalary = nSalary;

pObj->Delete = delete_Employee;

pObj->Display = Employee_DisplayInfo;

pObj->WriteToFile = Employee_WriteToFile;

return pObj;

}

Employee對象的結構

注意:從基類函數到派生類函數改變了接口(VTable)中指針位置。現在我們可以從基類(多態)訪問派生類函數。我們來看如何使用多態。

main()

{

Person* PersonObj = new_Person("pengdan", "farsight");

Person* EmployeeObj = new_Employee("kouxiaojuan", "liuyan","HR", "TCS", 40000);

PersonObj->Display(PersonObj);

PersonObj->WriteToFile(PersonObj,"persondata.txt");

PersonObj->Delete(PersonObj);

EmployeeObj->Display(EmployeeObj);

EmployeeObj->WriteToFile(EmployeeObj, "employeedata.txt");

EmployeeObj->Delete(EmployeeObj);

}

結論:

通過以上例子,我們看到使用c語言也可以實現封裝、繼承、多態,學習好以上知識會有助于我們更好的學習面向對象的語言。

4.Linux內核當中很多機制也有向對象的思想。

4.1下面我們以platform總線來分析

以下是platform總線重要的兩個結構體platform_device 和 platform_driver。

其中platform_driver中有個很重要的成員 struct device_driver driver;

該結構體是通用的驅動結構體函數,我們可以理解為一個基類,

以下是基于該總線實現的定義的platform_driver結構體變量

static struct platform_driver driver={

.probe = hello_probe,

.driver.name = "fs4412-beep",

.remove = hello_remove,

};

在這里我們可以看到我們對繼承過來的driver成員進行了賦值,我們跟蹤內核源碼platform_driver_register( )

我們可以看到此處,對driver的成員做了進一步賦值,對于driver結構體中幾個函數實現方法進行了重新賦值,

因為對于不論屬于哪種總線的驅動程序,都需要定義一個driver專用的結構體來維護驅動程序,比如I2C、spi、USB等。

這些總線在實現上

是不同的,但是linux內核要求不論那種總線都要有device_driver類型的成員,有些屬性和函數的實現是由device_driver繼承來的,類似于類的繼承的概念;但是有些成員和函數是要重新編寫的,這就類似于面向對象的多態,如在不同的總線下,probe、remove、shutdown幾種實現方法不一樣。

上一篇:C和C++中const的用法比較

下一篇:內核鏈表

熱點文章推薦
華清學員就業榜單
高薪學員經驗分享
熱點新聞推薦
前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,京ICP備16055225號-5京公海網安備11010802025203號

回到頂部

主站蜘蛛池模板: 久久久久国色AⅤ免费看 | 天天看片视频免费观看 | 亚洲AV无码一区东京热 | 无码不卡中文字幕av | 美女高潮无遮挡免费视频 | 狠狠躁夜夜躁人人爽天天不卡 | 人人爽久久久噜人人看 | 大狠狠大臿蕉香蕉大视频 | 老熟女草BX× | 欧洲美女黑人粗性暴交 | 人妻巨大乳挤奶水HD免费看 | 日本三级黄在线观看 | 国产欧美色一区二区三区 | 国产亚洲精品无码专区 | 久久人妻少妇偷人精品综合桃色 | 无码精品久久久天天影视 | 美女视频免费是黄的网站 | 免费无码成人片在线观看 | 无套内谢少妇毛片A片 | 国产在线高清精品二区 | 日日噜噜噜夜夜爽爽狠狠片 | 亚洲精品熟女国产 | 两个人看的www高清免费视频中文 | 久久婷婷五月综合中文字幕 | 无码人妻精品一区二区三区蜜桃 | 国产精品内射后入合集 | 妺妺窝人体色WWW婷婷 | 啪啪激情婷婷久久婷婷色五月 | 亚洲国精产品一二二线 | 日韩精品人妻中文字幕有码 | 爽到高潮无码视频在线观看 | 99亚洲乱人伦aⅴ精品 | 综合色区亚洲熟妇另类 | 午夜神器成在线人成在线人 | 精品国产一区AV天美传媒 | 欧美性猛交久久久乱大交 | 欧美bbw极品另类 | 国产亚洲精品久久久麻豆男与男 | 国产WWW麻豆传煤 | 久青草影院在线观看国产 | 亚洲精品成人网线在线播放va |