基於C語言的面向對象編程

来源:http://www.cnblogs.com/hyper99/archive/2016/04/28/ji-yuC-yu-yan-de-mian-xiang-dui-xiang-bian-cheng.html
-Advertisement-
Play Games

嵌入式軟體開發中,雖然很多的開發工具已經支持C++的開發,但是因為有時考慮運行效率和編程習慣,還是有很多人喜歡用C來開發嵌入式軟體。Miro Samek說:“我在開發現場發現,很多嵌入式軟體開發者(絕大多數是電子工程師)都有工作背景而且他們常常不喜歡用C++。”【1】面向對象編程(OOP)是一種方法... ...


嵌入式軟體開發中,雖然很多的開發工具已經支持C++的開發,但是因為有時考慮運行效率和編程習慣,還是有很多人喜歡用C來開發嵌入式軟體。Miro Samek說:“我在開發現場發現,很多嵌入式軟體開發者(絕大多數是電子工程師)都有工作背景而且他們常常不喜歡用C++。”【1】

面向對象編程(OOP)是一種方法,而不依賴於某特定語言。一般認為,OOP只能使用面向對象的語言,如Smalltalk、C++或Java等固有支持OOP的語言。但是,OOP並不依賴於特殊的語言,只要實現了OOP的封裝、繼承和多態性這三大基本特性,使用非固有支持面向對象的語言,也可以進行面向對象的編程。

面向對象編程方法的三大基本特性是:

  • 封裝性---封裝數據(屬性)與函數(方法)到類中的能力;
  • 繼承性---基於已有的類定義新類的能力;
  • 多態性---在運行時具有一致介面的對象相互替換的能力。

雖然這些特性與面向對象語言有關,但幾乎可以用任何語言實現面向對象的這三大基本特性,包括C語言和彙編語言等。事實上,不管實現語言為何,任何大的軟體系統幾乎都會以某種形式使用抽象(封裝)、繼承或多態性。

1.C語言的封裝

1.1 封裝的本質

在C++中,一個類中包括屬性和方法,聲明一個類例子如下:

class A {
  int n;                 //屬性
  A();                   //構造函數
  void function1(int x){...}; //方法
}

在C++中,用A生成兩個對象a1和a2時,如下:

A a1 = new A();
A a2 = new A();

對於非模板類A,在記憶體中,對所有的對象,方法function1只有一個拷貝,而對每個對象,都有自己獨立的一份屬性拷貝,也就是有多個屬性拷貝,所謂創建一個對象,也就是創建一套屬性。

調用a1.function1()和a2.function1()時,每個對象使用自己的屬性n1和n2,而方法代碼在記憶體中是同一套。這就相當於調用functin1(n1,x)和function1(n2,x)。

在C語言實現中,把所有的屬性放到一個結構中,所有方法中第一個參數用一個指向自己屬性結構的一個指針me, 如下:
function1(struct *me, ...);
這個方法對所有對象有用,具體對哪個對象的屬性操作,可以用me來區分。

1.2 具體例子

生成兩個文件person.h和person.c,定義一個Person結構類型(也就是類名稱),把屬性放到結構中方法中的第一個參數me是Person的引用指針

pers1.2on.h文件:
在頭文件中以結構定義類成員屬性,聲明構造方法和析構方法,聲明public方法。

#ifndef PERSON_H
#define PERSON_H

    /*1.定義類成員屬性(沒有隱藏)*/
    typedef struct PersonTag {
        String name__; /*屬性*/
        uint8_t age__; /*屬性*/
    }Person;  
      
    /*2.聲明構造和析構函數*/
    void Person_Ctor(Person *me, uint8_t age);/*第一個參數指向屬性*/
    void Person_Xtor(Person *me);/*第一個參數指向屬性*/

    
    /*3.聲明public方法*/
    void Person_setName(Person *me, String name);/*第一個參數指向屬性*/
    String Person_getName(Person *me);/*第一個參數指向屬性*/
    
    /*4.聲明private方法(要在person.c文件中聲明)*/ 
      
#endif

person.c文件:
在.c文件中聲明private方法,並實現所有的方法。

#include "person.h"

/*1.聲明private方法, 用static修飾*/
static void Person_setAge(Person *me, uint8_t age);/*第一個參數指向屬性*/
static uint8_t Person_getAge(Person *me);/*第一個參數指向屬性*/

/*2.實現構造和析構函數*/
void Person_Ctor(Person *me, uint8_t age) {
    me->age__ = age;
}
void Person_Xtor(Person *me) {
    ...
}

/*3.實現public方法*/
void Person_setName(Person *me, String name) {
    me->name__ = name;
}
String Person_getName(Person *me) {
    return me->name__;
}

/*4.實現private方法*/
void Person_setAge(Person *me, uint8_t age) {
    me->age__ = age;
}
uint8_t Person_getAge(Person *me) {
    return me->age__;
}

app.c中使用Person類:

#include "person.h"  /*包含頭*/
void main() {
    String tmp;
    Person l_ps1; /*創建一個實例,實際就是一個屬性*/
    Person l_ps2; /*創建另一個實例,實際就是另一個屬性*/
    
    Person_Ctor(l_ps1, 30);      /*顯式調用構造函數*/
    Person_setName(l_ps1,"張三"); /*使用其public方法*/
    tmp = Person_getName(l_ps1); /*使用其public方法*/
    
    Person_Ctor(l_ps2, 30);       /*使用其public方法*/
    Person_setName(l_ps2, "李四"); /*使用其public方法*/
    tmp = Person_getName(l_ps2);  /*使用其public方法*/
}

2.C語言的繼承

Student繼承自Person, 繼承類屬性結構的第一個參數指向父類屬性,這樣可以滿足Liskov替換原則

student.h文件:
在頭文件中以結構定義類成員屬性,並聲明構造、析構函數和public方法。

#ifndef STUDENT_H
#define STUDENT_H
#include "person.h"  /*包含父類頭*/

    /*1.定義類屬性(沒有隱藏)*/
    typedef struct StudentTag {
        Person super;   /*第一個參數指向父類Person,繼承父類屬性*/
        uint8_t code__; /*子類添加的屬性*/
    }Student;  
      
    /*2.聲明構造和析構方法*/
    void Student_Ctor(Student *me, uint8_t code);
    void Student_Xtor(Student *me);
    
    /*3.聲明public方法*/
    void Student_setCode(Student *me, uint8_t code);
    uint8_t Student_getCode(Student *me);
    
    /*4.聲明private方法(在.c文件中聲明)*/ 
      
#endif

student.c文件:
在.c文件中聲明private方法,實現所有的構造方法和析構方法,實現所有的public和private方法。

#include "student.h"

/*1.聲明private方法*/
static void XXX(Student *me, ...);
 

/*2.構造和析構方法實現*/
void Student_Ctor(Student *me, String name, uint8_t code) {
    Person_Ctor((Person*)me, name);/*先調用父類構造函數*/
    me->code__ = code;
}
void Person_Xtor(Person *me) {
    ...
}

/*3.public方法實現*/
void Student_setCode(Student *me, uint8_t code) {
    me->code__ = code;
}
 

app.c中使用Student類:

#include "Student.h"  /*包含頭*/
void main() {
    String tmp;
    Student l_st1; /*創建一個實例,實際就是一個屬性*/
    Student l_st2; /*創建另一個實例,實際就是另一個屬性*/
    
    Student_Ctor(l_st1, "張三, 25);  /*顯式調用構造函數*/
    Student_setCode(l_st1, 30); //使用其public方法
    tmp = Student_getCode(l_st1); //使用其public方法
}

3.C語言的多態性

利用C語言的萬能指針void *p可以實現多態。略。

4.總結

用C語言可以實現面向對象的三大特性,適合於嵌入式系統的編程,QP的C版本就是這樣實現的。現在很多的開源軟體,包括postgreSQL、GObject等都採用C語言實現面向對象的方法。採用這個方法,使程式具有更好的可讀性、可擴展性,同時保持了C語言的高效性。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ElasticSearch - 嵌套映射和過濾器 Because nested objects are indexed as separate hidden documents, we can’t query them directly. Instead, we have to use the ne ...
  • 備份類型: 完全備份 部分備份:僅備份其中的一張表或多張表 增量備份:僅備份從上次完全備份或增量備份之後變化的數據部分 熱備份:線上備份,讀寫操作不受影響 溫備份:線上備份,讀操作可繼續進行,但寫操作不允許 冷備份:離線備份,資料庫伺服器離線,備份期間不能為業務提供讀寫服務 物理備份:直接複製數據文 ...
  • 培訓Spark架構開發! 從基礎到高級,一對一培訓![技術QQ:2937765541] 課程體系: 獲取視頻資料和培訓解答技術支持地址 課程展示(大數據技術很廣,一直線上為你培訓解答!): 獲取視頻資料和培訓解答技術支持地址 ...
  • 培訓大數據架構開發、挖掘分析! 從零基礎到高級,一對一培訓![技術QQ:2937765541] 課程體系: 獲取視頻資料和培訓解答技術支持地址 課程展示(大數據技術很廣,一直線上為你培訓解答!): 獲取視頻資料和培訓解答技術支持地址 ...
  • 首先,介紹一下Redis資料庫。Redis是一種面向“鍵/值”對數據類型的記憶體資料庫,可以滿足我們對海量數據的讀寫需求。 1)redis的鍵只能是字元串; 2)redis的值支持多種數據類型: a:字元串 string b:哈希 hash c:字元串列表 list d:字元串集合 set 不重覆,無 ...
  • 由於前一段時間胃痛,導致博客園博客都停更了一個月左右。近幾天,胃病終於稍微有所好轉,決定重新寫博文。 前幾天,有個朋友剛好問到本人有關 SQL 語句,大致是原表有兩列,分別為月份、月份銷售額,而需要一條 SQL 語句實現統計出每個月份以及當前月以前月份銷售額和。尼瑪,感覺還是沒有說清,下麵用圖表示。 ...
  • mysql copy表或表數據常用的語句整理彙總. 假如我們有以下這樣一個表: 1. 下麵這個語句會拷貝表結構到新表newadmin中。 (不會拷貝表中的數據) 2. 下麵這個語句會拷貝數據到新表中。 註意:這個語句其實只是把select語句的結果建一個表。所以newadmin這個表不會有主鍵,索引 ...
  • 查詢作業的執行情況sql: step:作業的第幾個步驟。其中0為結果。 step:對應步驟的名字。 即是查作業的歷史記錄。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...