用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;
}
/<iostream>


用C語言寫面向的對象是一種什麼樣的體驗?

C語言


編譯後輸出:


用C語言寫面向的對象是一種什麼樣的體驗?

C語言


以上便是簡單工廠模式的源碼示例,現在,我們來聊聊為什麼用C語言我們也可以實現這面向對象思維的三大特性:



首先是封裝性:C++的封裝性就是將抽象類的函數和屬性都封裝起來,不對外開放,外部要使用這些屬性和方法都必須通過一個具體實例對象去訪問這些方法和屬性,而我們知道,C語言中一旦包含了頭文件便可以使用頭文件中的函數和變量,其實C語言中也可以用一種方法達到這種效果,那便是使用結構體+函數指針+static,結構體中定義屬性和函數指針,static將方法都限制在本模塊使用,對外部,通過指針函數的方式訪問,如此一來,便可以達到面向對象封裝性的實現;



對於繼承性:C++ 面向對象的繼承是可以繼承父類的屬性和方法,在子類對象中的內存中是有父類對象的內存的,那麼,用C語言來寫的話我們完全可以在父類結構體中定義一個父類變量在其中,在使用構造子類的時候同時構造父類,便可以達到繼承性的特性;



對於多態性:C++中允許一個父類指針指向子類實體,在這個指針使用方法時,若此方法是虛函數,則執行動作會執行到具體的子類函數中,本質的實現方式是通過一個虛函數指針的方式,由於我們用C語言寫面向對象本就是通過函數指針的方式來封裝函數,那我們完全可以將結構體父類的變量的函數指針讓他指向子類的函數來達到多態的特性。


加C/C++學習交.流群,免費獲取C語言、C++學習資料,學習路線指導和梳理,更有進階乾貨的直播免費學習權限 ,都是大牛帶飛 讓你少走很多的彎路的 群...號是 546912356


好了,在你們面前班門弄斧了一番,下面開始具體的代碼實現:

頭文件:

#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_ */
/<stdlib.h>/<stdio.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;
}
/<stdio.h>

編譯後執行:


用C語言寫面向的對象是一種什麼樣的體驗?

C語言


以上的結果可以看出,我們的測試代碼接口都是一樣的,效果達到了C++面向對象的設計理念,用C語言完成了一次狠狠的逆襲,希望大家在你們的項目工程中有幫助。

用C語言寫面向的對象是一種什麼樣的體驗?

C語言


其實程序員的工作大部分是寫代碼,但是代碼的閱讀對象往往並不是我們自己,將我們的思維寫進去才是一個程序員的境界,不要簡單的根據流程去寫一個代碼,否則,程序員就真的只是一個工具了;

哦,BTW,在函數中使用了本結構體的指針在裡面,是為了達到在函數中使用示例的屬性,這樣就獨立每一個示例的屬性操作了。


分享到:


相關文章: