1. 程式人生 > >C語言實現封裝、繼承和多型

C語言實現封裝、繼承和多型

雖然C語言一直被稱為面向過程的設計語言,但是通過使用C語言函式指標和結構體的特性,還是能夠使用C語言實現類似面向物件的封裝、繼承和多型的概念。

下面對原始碼進行分析:

validator.h檔案

首先提取了所有校驗器都有的校驗方法,定義了一個校驗器抽象類Validator,然後定義範圍校驗器類RangeValidator,該類繼承自校驗類Validator,幷包含了範圍校驗器特有的屬性min和max。

#ifndef _VALIDATOR_H_
#define _VALIDATOR_H_

#include <stdbool.h>

/* 定義校驗器抽象類 */
typedef struct _Validator
{
    bool (*validate)(struct _Validator *pThis, int value);
}Validator;

/* 定義範圍校驗器類 */
typedef struct
{
    Validator isa;
    const int min;
    const int max;
}RangeValidator;

/* 定義奇偶校驗器類 */
typedef struct
{
    Validator isa;
    bool isEven;
}OddEvenValidator;

bool validateRange(Validator *pThis, int value);        //範圍校驗器函式
bool validateOddEven(Validator *pThis, int value);      //基偶校驗器函式

#define newRangeValidator(min, max) {{validateRange}, (min), (max)} //初始化RangeValidator
#define newOddEvenValidator(isEven) {{validateOddEven}, (isEven)}   //初始化OddEvenValidator

#endif // _VALIDATOR_H_

validator.c檔案

分別實現,繼承自校驗器類的校驗方法,使不同的物件呼叫同一方法,能夠完成不同的結果,實現多型特性。

#include "validator.h"

/* 實現範圍校驗的方法 */
bool validateRange(Validator *pThis, int value)
{
    RangeValidator *pRangeValidator = (RangeValidator *)pThis;

    return (pRangeValidator->min <= value && value <= pRangeValidator->max);
}

/* 實現奇偶校驗的方法 */
bool validateOddEven(Validator *pThis, int value)
{
    OddEvenValidator *pOddEvenValidator = (OddEvenValidator *)pThis;

    return (!pOddEvenValidator->isEven && (value % 2)) ||
           (pOddEvenValidator->isEven && !(value % 2));
}

main.c檔案

使用巨集定義來實現new方法,並在物件建立時,將方法和屬性給類結構體賦值。在C語言中,表達意思就是通過巨集定義給函式指標和變數賦值。

#include <stdio.h>
#include <stdlib.h>
#include "validator.h"

int main()
{
    int rangeResult = 0;
    int isEvenResult = 0;

    RangeValidator rangeValidator = newRangeValidator(1, 9);        //建立範圍校驗器物件
    OddEvenValidator oddEvenValidator = newOddEvenValidator(1);     //建立奇偶校驗器物件

    rangeResult = rangeValidator.isa.validate(&rangeValidator, 12);
    isEvenResult = oddEvenValidator.isa.validate(&oddEvenValidator, 4);

    printf("rangeResult:%d, isEvenResult:%d", rangeResult, isEvenResult);

    return 0;
}