用C語(yǔ)言寫(xiě)面向的對(duì)象是一種什么樣的體驗(yàn)
最近從老東家離職,跳出來(lái)跟這幾個(gè)以前的老同事,拉了一個(gè)創(chuàng)業(yè)團(tuán)隊(duì),準(zhǔn)備干一票,去之前也了解了一番,此次將使用C語(yǔ)言來(lái)開(kāi)發(fā),對(duì)于畢業(yè)之后一直從事C++面向?qū)ο笏季S編碼的我來(lái)說(shuō),雖然不舍,但是仔細(xì)想了下,這都不是事,誰(shuí)說(shuō)用C語(yǔ)言寫(xiě)不了面向?qū)ο螅?/p>
眾所周知面向?qū)ο蟮娜齻€(gè)特性:封裝性、繼承性、多態(tài)性。這幾個(gè)特性的具體含義我等會(huì)會(huì)班門(mén)弄斧講一下含義,下面,請(qǐng)?jiān)试S我先用C++面向?qū)ο笏季S將設(shè)計(jì)模式中最常用的簡(jiǎn)單工廠模式寫(xiě)一邊,相信這三個(gè)特性不言而喻。
以下我將用一個(gè)工廠類實(shí)現(xiàn)具體汽車的生產(chǎn),奔馳車、寶馬車、奧迪車都將通過(guò)工廠類來(lái)生產(chǎn),由父類指針指向具體的汽車實(shí)例:
頭文件:
//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;
}
測(cè)試代碼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;
}
編譯后輸出:
以上便是簡(jiǎn)單工廠模式的源碼示例,現(xiàn)在,我們來(lái)聊聊為什么用C語(yǔ)言我們也可以實(shí)現(xiàn)這面向?qū)ο笏季S的三大特性:
首先是封裝性:C++的封裝性就是將抽象類的函數(shù)和屬性都封裝起來(lái),不對(duì)外開(kāi)放,外部要使用這些屬性和方法都必須通過(guò)一個(gè)具體實(shí)例對(duì)象去訪問(wèn)這些方法和屬性,而我們知道,C語(yǔ)言中一旦包含了頭文件便可以使用頭文件中的函數(shù)和變量,其實(shí)C語(yǔ)言中也可以用一種方法達(dá)到這種效果,那便是使用結(jié)構(gòu)體+函數(shù)指針+static,結(jié)構(gòu)體中定義屬性和函數(shù)指針,static將方法都限制在本模塊使用,對(duì)外部,通過(guò)指針函數(shù)的方式訪問(wèn),如此一來(lái),便可以達(dá)到面向?qū)ο蠓庋b性的實(shí)現(xiàn);
對(duì)于繼承性:C++ 面向?qū)ο蟮睦^承是可以繼承父類的屬性和方法,在子類對(duì)象中的內(nèi)存中是有父類對(duì)象的內(nèi)存的,那么,用C語(yǔ)言來(lái)寫(xiě)的話我們完全可以在父類結(jié)構(gòu)體中定義一個(gè)父類變量在其中,在使用構(gòu)造子類的時(shí)候同時(shí)構(gòu)造父類,便可以達(dá)到繼承性的特性;
對(duì)于多態(tài)性:C++中允許一個(gè)父類指針指向子類實(shí)體,在這個(gè)指針使用方法時(shí),若此方法是虛函數(shù),則執(zhí)行動(dòng)作會(huì)執(zhí)行到具體的子類函數(shù)中,本質(zhì)的實(shí)現(xiàn)方式是通過(guò)一個(gè)虛函數(shù)指針的方式,由于我們用C語(yǔ)言寫(xiě)面向?qū)ο蟊揪褪峭ㄟ^(guò)函數(shù)指針的方式來(lái)封裝函數(shù),那我們完全可以將結(jié)構(gòu)體父類的變量的函數(shù)指針讓他指向子類的函數(shù)來(lái)達(dá)到多態(tài)的特性。
好了,在你們面前班門(mén)弄斧了一番,下面開(kāi)始具體的代碼實(shí)現(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;
}
測(cè)試文件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í)行:
以上的結(jié)果可以看出,我們的測(cè)試代碼接口都是一樣的,效果達(dá)到了C++面向?qū)ο蟮脑O(shè)計(jì)理念,用C語(yǔ)言完成了一次狠狠的逆襲,希望讀者朋友在你的項(xiàng)目工程中有幫助。其實(shí)程序員的工作大部分是寫(xiě)代碼,但是代碼的閱讀對(duì)象往往并不是我們自己,將我們的思維寫(xiě)進(jìn)去才是一個(gè)程序員的境界,不要簡(jiǎn)單的根據(jù)流程去寫(xiě)一個(gè)代碼,否則,程序員就真的只是一個(gè)工具了;
哦,BTW,在函數(shù)中我使用了本結(jié)構(gòu)體的指針在里面,是為了達(dá)到在函數(shù)中使用示例的屬性,這樣就獨(dú)立每一個(gè)示例的屬性操作了。