用C語言寫面向的物件是一種什麼樣的體驗
最近從老東家離職,跳出來跟這幾個以前的老同事,拉了一個創業團隊,準備幹一票,去之前也瞭解了一番,此次將使用C語言來開發,對於畢業之後一直從事C++物件導向思維編碼的我來說,雖然不捨,但是仔細想了下,這都不是事,誰說用C語言寫不了物件導向?
眾所周知物件導向的三個特性:封裝性、繼承性、多型性。這幾個特性的具體含義我等會會班門弄斧講一下含義,下面,請允許我先用C++物件導向思維將設計模式中最常用的簡單工廠模式寫一邊,相信這三個特性不言而喻。
以下我將用一個工廠類實現具體汽車的生產,賓士車、寶馬車、奧迪車都將通過工廠類來生產,由父類指標指向具體的汽車例項:
標頭檔案:
//Car.h #ifndef CAR_H_ #define CAR_H_ typedef enum CarType_E { CAR_TYPE_BENZE = 0, CAR_TYPE_BMW , CAR_TYPE_AUDI , CAR_TYPE_NONE , }CarType_E; class BaseCar { public: BaseCar(CarType_E CarType); virtual ~BaseCar(); virtual void CarSpeaker(); CarType_E _CarType; }; class BenzeCar : public BaseCar { public: BenzeCar(CarType_E CarType); ~BenzeCar(); public: void CarSpeaker(); }; class BMWCar : public BaseCar { public: BMWCar(CarType_E CarType); ~BMWCar(); void CarSpeaker(); }; class AudiCar : public BaseCar { public: AudiCar(CarType_E CarType); ~AudiCar(); void CarSpeaker(); }; class CarFactory { public: BaseCar* createNewCar(CarType_E CarType); }; #endif /* CAR_H_ */
原始碼:
//Car.cpp #include "Car.h" #include <iostream> using namespace std; BaseCar::BaseCar(CarType_E CarType) : _CarType(CarType) { printf("BaseCar create\n"); } BaseCar::~BaseCar() { printf("BaseCar delete\n"); } void BaseCar::CarSpeaker() { std::cout << "BeBu! BeBu" << endl; } BenzeCar::BenzeCar(CarType_E CarType) : BaseCar(CarType) { printf("BenzeCar create\n"); } BenzeCar::~BenzeCar() { printf("BenzeCar delete\n"); } void BenzeCar::CarSpeaker() { printf("BeBu! BeBu! BenzeCar Car,Type:%d\n", _CarType); } BMWCar::BMWCar(CarType_E CarType) : BaseCar(CarType) { printf("BMWCar create\n"); } BMWCar::~BMWCar() { printf("BMWCar delete\n"); } void BMWCar::CarSpeaker() { printf("BeBu! BeBu! BMWCar Car,Type:%d\n", _CarType); } AudiCar::AudiCar(CarType_E CarType) : BaseCar(CarType) { printf("AudiCar create\n"); } AudiCar::~AudiCar() { printf("AudiCar delete\n"); } void AudiCar::CarSpeaker() { printf("BeBu! BeBu! AudiCar Car,Type:%d\n", _CarType); } BaseCar* CarFactory::createNewCar(CarType_E CarType) { BaseCar* newCar = NULL; switch(CarType) { case CAR_TYPE_BENZE: { newCar = new BenzeCar(CAR_TYPE_BENZE); break; } case CAR_TYPE_BMW: { newCar = new BMWCar(CAR_TYPE_BMW); break; } case CAR_TYPE_AUDI: { newCar = new AudiCar(CAR_TYPE_AUDI); break; } default: { newCar = new BaseCar(CAR_TYPE_NONE); break; } } return newCar; }
測試程式碼main.cpp
//main.cpp #include <iostream> #include "Car.h" using namespace std; int main() { CarFactory* carFactory = new CarFactory(); BaseCar* newBenzeCar = carFactory->createNewCar(CAR_TYPE_BENZE); BaseCar* newBMWCar = carFactory->createNewCar(CAR_TYPE_BMW); BaseCar* newAudiCar = carFactory->createNewCar(CAR_TYPE_AUDI); newBenzeCar->CarSpeaker(); newBMWCar->CarSpeaker(); newAudiCar->CarSpeaker(); delete newBenzeCar; newBenzeCar = NULL; delete newBMWCar; newBMWCar = NULL; delete newAudiCar; newAudiCar = NULL; delete carFactory; carFactory = NULL; return 0; }
編譯後輸出:
以上便是簡單工廠模式的原始碼示例,現在,我們來聊聊為什麼用C語言我們也可以實現這物件導向思維的三大特性:
首先是封裝性:C++的封裝性就是將抽象類的函式和屬性都封裝起來,不對外開放,外部要使用這些屬性和方法都必須通過一個具體例項物件去訪問這些方法和屬性,而我們知道,C語言中一旦包含了標頭檔案便可以使用標頭檔案中的函式和變數,其實C語言中也可以用一種方法達到這種效果,那便是使用結構體+函式指標+static,結構體中定義屬性和函式指標,static將方法都限制在本模組使用,對外部,通過指標函式的方式訪問,如此一來,便可以達到物件導向封裝性的實現;
對於繼承性:C++ 物件導向的繼承是可以繼承父類的屬性和方法,在子類物件中的記憶體中是有父類物件的記憶體的,那麼,用C語言來寫的話我們完全可以在父類結構體中定義一個父類變數在其中,在使用構造子類的時候同時構造父類,便可以達到繼承性的特性;
對於多型性:C++中允許一個父類指標指向子類實體,在這個指標使用方法時,若此方法是虛擬函式,則執行動作會執行到具體的子類函式中,本質的實現方式是通過一個虛擬函式指標的方式,由於我們用C語言寫物件導向本就是通過函式指標的方式來封裝函式,那我們完全可以將結構體父類的變數的函式指標讓他指向子類的函式來達到多型的特性。
好了,在你們面前班門弄斧了一番,下面開始具體的程式碼實現:
標頭檔案:
#ifndef CAR_H_ #define CAR_H_ #include <stdio.h> #include <stdlib.h> typedef enum CarType { CAR_BENZE = 0, CAR_BMW, CAR_AUDI, CAR_NONE, }CarType; typedef struct Base_Car { CarType car_type; void (* speaker)(struct Base_Car* car); void* parent_car; //point to parent,if no any parent,then make it NULL }Base_Car; typedef struct Benze_Car { Base_Car* car; void (* speaker)(struct Base_Car* car); }Benze_Car; typedef struct BMW_Car { Base_Car* car; void (* speaker)(struct Base_Car* car); }BMW_Car; typedef struct Audi_Car { Base_Car* car; void (* speaker)(struct Base_Car* car); }Audi_Car; typedef struct Car_Factory { Base_Car* (* create_new_car)(CarType car_type); }Car_Factory; Car_Factory* new_car_factory(); void delete_car_factory(Car_Factory* car_factory); Base_Car* new_Base_Car(); Benze_Car* new_benze_Car(); BMW_Car* new_bmw_Car(); Audi_Car* new_audi_Car(); void delete_Base_Car(struct Base_Car* car); void delete_Benze_Car(struct Benze_Car* car); void delete_BMW_Car(struct BMW_Car* car); void delete_Audi_Car(struct Audi_Car* car); #endif /* CAR_H_ */
原始檔:
#include "Car.h" static void Car_speaker(struct Base_Car* car) { printf("this is a car\n"); } static void Benze_speaker(struct Base_Car* car) { printf("this is Benze Car, car type is :%d\n",car->car_type); } static void BMW_speaker(struct Base_Car* car) { printf("this is BMW Car, car type is :%d\n",car->car_type); } static void Audi_speaker(struct Base_Car* car) { printf("this is Audi Car, car type is :%d\n",car->car_type); } Benze_Car* new_benze_Car() { Benze_Car* real_car = (Benze_Car*)malloc(sizeof(Benze_Car)); Base_Car* base_car = new_Base_Car(); printf("Benze_Car create\n"); real_car->car = base_car; real_car->speaker = Benze_speaker; base_car->car_type = CAR_BENZE; base_car->parent_car = (void*)real_car; base_car->speaker = real_car->speaker; return real_car; } BMW_Car* new_bmw_Car() { BMW_Car* real_car = (BMW_Car*)malloc(sizeof(BMW_Car)); Base_Car* base_car = new_Base_Car(); printf("BMW_Car create\n"); base_car->car_type = CAR_BMW; real_car->car = base_car; real_car->speaker = BMW_speaker; base_car->car_type = CAR_BMW; base_car->parent_car = (void*)real_car; base_car->speaker = real_car->speaker; return real_car; } Audi_Car* new_audi_Car() { Audi_Car* real_car = (Audi_Car*)malloc(sizeof(Audi_Car)); Base_Car* base_car = new_Base_Car(); printf("Audi_Car create\n"); base_car->car_type = CAR_AUDI; real_car->car = base_car; real_car->speaker = Audi_speaker; base_car->car_type = CAR_AUDI; base_car->parent_car = (void*)real_car; base_car->speaker = real_car->speaker; return real_car; } Base_Car* new_Base_Car() { Base_Car* base_car = (Base_Car*)malloc(sizeof(Base_Car)); printf("BaseCar create\n"); base_car->car_type = CAR_NONE; base_car->parent_car = NULL; base_car->speaker = Car_speaker; return base_car; } Base_Car* create_new_Car(CarType car_type) { Base_Car* base_car = NULL; switch(car_type) { case CAR_BENZE: { Benze_Car* real_car = new_benze_Car(); base_car = real_car->car; break; } case CAR_BMW: { BMW_Car* real_car = new_bmw_Car(); base_car = real_car->car; break; } case CAR_AUDI: { Audi_Car* real_car = new_audi_Car(); base_car = real_car->car; break; } default: break; } return base_car; } void delete_Benze_Car(struct Benze_Car* car) { free(car->car); car->car = NULL; free(car); printf("Benze_Car delete\n"); } void delete_BMW_Car(struct BMW_Car* car) { free(car->car); car->car = NULL; free(car); printf("BMW_Car delete\n"); } void delete_Audi_Car(struct Audi_Car* car) { free(car->car); car->car = NULL; free(car); printf("Audi_Car delete\n"); } void delete_Base_Car(struct Base_Car* car) { if(NULL != car->parent_car) { switch(car->car_type) { case CAR_BENZE: { delete_Benze_Car((Benze_Car*)car->parent_car); car = NULL; //base car will be delete in child free function break; } case CAR_BMW: { delete_BMW_Car((BMW_Car*)car->parent_car); car = NULL; break; } case CAR_AUDI: { delete_Audi_Car((Audi_Car*)car->parent_car); car = NULL; break; } default: break; } } if(NULL != car) { free(car); car = NULL; } printf("Base_Car delete\n"); } Car_Factory* new_car_factory() { Car_Factory* car_factory = (Car_Factory*)malloc(sizeof(Car_Factory)); car_factory->create_new_car = create_new_Car; return car_factory; } void delete_car_factory(Car_Factory* car_factory) { free(car_factory); car_factory = NULL; }
測試檔案main.cpp
#include <stdio.h> #include "Car.h" int main() { Car_Factory* car_factory = new_car_factory(); Base_Car* benzeCar = car_factory->create_new_car(CAR_BENZE); Base_Car* bmwCar = car_factory->create_new_car(CAR_BMW); Base_Car* audiCar = car_factory->create_new_car(CAR_AUDI); benzeCar->speaker(benzeCar); bmwCar->speaker(bmwCar); audiCar->speaker(audiCar); delete_Base_Car(benzeCar); benzeCar = NULL; delete_Base_Car(bmwCar); bmwCar = NULL; delete_Base_Car(audiCar); audiCar = NULL; delete_car_factory(car_factory); car_factory = NULL; return 0; }
編譯後執行:
以上的結果可以看出,我們的測試程式碼介面都是一樣的,效果達到了C++物件導向的設計理念,用C語言完成了一次狠狠的逆襲,希望讀者朋友在你的專案工程中有幫助。其實程式設計師的工作大部分是寫程式碼,但是程式碼的閱讀物件往往並不是我們自己,將我們的思維寫進去才是一個程式設計師的境界,不要簡單的根據流程去寫一個程式碼,否則,程式設計師就真的只是一個工具了;
哦,BTW,在函式中我使用了本結構體的指標在裡面,是為了達到在函式中使用示例的屬性,這樣就獨立每一個示例的屬性操作了。
相關文章
- 用 C 語言寫面向的物件是一種什麼樣的體驗物件
- 在大公司寫程式碼是一種什麼樣的體驗?
- 被文獻坑是一種什麼樣的體驗?
- Go是一門什麼樣的語言?Go
- 用Kotlin改寫PHP程式是什麼樣的體驗KotlinPHP
- 在MacBook上使用Win 10是一種什麼樣的體驗Mac
- 深度學習中資料集很小是一種什麼樣的體驗深度學習
- 在Android上使用JS引擎是一種什麼樣的體驗?AndroidJS
- 在小公司程式設計是一種什麼樣的體驗?程式設計
- 在Excel VBA中寫SQL,是一種什麼體驗ExcelSQL
- 最終一輪面試被 Google 刷掉,這是一種什麼樣的體驗?面試Go
- 在 2016 年學 JavaScript 是一種什麼樣的體驗?JavaScript
- 第一個C語言編譯器是怎樣編寫的?C語言編譯
- 第一個 C 語言編譯器是怎樣編寫的?編譯
- C語言 EOF是什麼?C語言
- 搶先體驗! 在瀏覽器裡寫 Flutter 是一種什麼體驗?瀏覽器Flutter
- 當 dotnet-monitor 遇上 Prometheus, 是種什麼樣的體驗?Prometheus
- 在 2016 年學 Android 是一種什麼樣的體驗?Android
- 什麼是Python?python是一門怎樣的程式語言?Python
- 為什麼Go是一種設計糟糕的程式語言Go
- 和自己的學生一起開發獨立遊戲,是種什麼樣的體驗?遊戲
- 《新神》開發者:獨立遊戲開發是種什麼樣的體驗?遊戲開發
- 在騰訊工作是一種怎樣的體驗?
- 新學一種c語言寫法C語言
- 現代程式語言用什麼語言寫成?
- 30歲轉行做初級程式設計師是一種什麼樣的體驗?程式設計師
- 為什麼《七週七語言》選中的是這幾種語言?
- python和c語言的區別是什麼PythonC語言
- 當一名阿里P9是什麼樣的體驗?阿里
- 作為一個開源軟體的作者是一種什麼樣的感受?
- 【開源訪談】厲華:寫一個開源容器引擎會是什麼樣的體驗?
- 為什麼 C# 可能是最好的第一程式語言C#
- python爬蟲是什麼?為什麼用python語言寫爬蟲?Python爬蟲
- C語言:一種高效、易學的程式語言C語言
- 同時拿到BATJMD的Offer是怎樣的一種體驗?BAT
- 影片需求超平常數 10 倍,卻節省了 60% 的 IT 成本投入是一種什麼樣的體驗?
- 在阿里安全工作是一種怎樣的體驗阿里
- 一種新的面嚮物件語言――Other語言(暫定名)物件R語言