用C語言寫面向的對象是一種什么樣的體驗
最近從老東家離職,跳出來跟這幾個以前的老同事,拉了一個創(chuàng)業(yè)團隊,準備干一票,去之前也了解了一番,此次將使用C語言來開發(fā),對于畢業(yè)之后一直從事C++面向對象思維編碼的我來說,雖然不舍,但是仔細想了下,這都不是事,誰說用C語言寫不了面向對象?
眾所周知面向對象的三個特性:封裝性、繼承性、多態(tài)性。這幾個特性的具體含義我等會會班門弄斧講一下含義,下面,請允許我先用C++面向對象思維將設計模式中最常用的簡單工廠模式寫一邊,相信這三個特性不言而喻。
以下我將用一個工廠類實現(xiàn)具體汽車的生產(chǎn),奔馳車、寶馬車、奧迪車都將通過工廠類來生產(chǎn),由父類指針指向具體的汽車實例:
頭文件:
//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;  
}
編譯后輸出:

以上便是簡單工廠模式的源碼示例,現(xiàn)在,我們來聊聊為什么用C語言我們也可以實現(xiàn)這面向對象思維的三大特性:
首先是封裝性:C++的封裝性就是將抽象類的函數(shù)和屬性都封裝起來,不對外開放,外部要使用這些屬性和方法都必須通過一個具體實例對象去訪問這些方法和屬性,而我們知道,C語言中一旦包含了頭文件便可以使用頭文件中的函數(shù)和變量,其實C語言中也可以用一種方法達到這種效果,那便是使用結構體+函數(shù)指針+static,結構體中定義屬性和函數(shù)指針,static將方法都限制在本模塊使用,對外部,通過指針函數(shù)的方式訪問,如此一來,便可以達到面向對象封裝性的實現(xiàn);
對于繼承性:C++ 面向對象的繼承是可以繼承父類的屬性和方法,在子類對象中的內(nèi)存中是有父類對象的內(nèi)存的,那么,用C語言來寫的話我們完全可以在父類結構體中定義一個父類變量在其中,在使用構造子類的時候同時構造父類,便可以達到繼承性的特性;
對于多態(tài)性:C++中允許一個父類指針指向子類實體,在這個指針使用方法時,若此方法是虛函數(shù),則執(zhí)行動作會執(zhí)行到具體的子類函數(shù)中,本質(zhì)的實現(xiàn)方式是通過一個虛函數(shù)指針的方式,由于我們用C語言寫面向對象本就是通過函數(shù)指針的方式來封裝函數(shù),那我們完全可以將結構體父類的變量的函數(shù)指針讓他指向子類的函數(shù)來達到多態(tài)的特性。
好了,在你們面前班門弄斧了一番,下面開始具體的代碼實現(xiàn):
頭文件:
#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;  
}
編譯后執(zhí)行:

以上的結果可以看出,我們的測試代碼接口都是一樣的,效果達到了C++面向對象的設計理念,用C語言完成了一次狠狠的逆襲,希望讀者朋友在你的項目工程中有幫助。其實程序員的工作大部分是寫代碼,但是代碼的閱讀對象往往并不是我們自己,將我們的思維寫進去才是一個程序員的境界,不要簡單的根據(jù)流程去寫一個代碼,否則,程序員就真的只是一個工具了;
哦,BTW,在函數(shù)中我使用了本結構體的指針在里面,是為了達到在函數(shù)中使用示例的屬性,這樣就獨立每一個示例的屬性操作了。















 
 
 




 
 
 
 