C語言簡(jiǎn)單實(shí)現(xiàn)面向?qū)ο笏枷?/h2>

C語言和C++都會(huì)經(jīng)過匯編,生成匯編代碼,在匯編代碼的階段,是分辨不出是C語言還是C++語言的。在早期C++還沒有成熟的編譯器的時(shí)候,C++通過先把程序翻譯成C語言,然后使用C語言的編譯器把程序編譯成可執(zhí)行文件。所以,面向?qū)ο笾皇且环N思想,在不支持面向?qū)ο蟮恼Z言中也可以使用這種思想。只不過,在C語言中,需要自己實(shí)現(xiàn)這些特性,而在C++中,是編譯器在幕后做了一些工作。

數(shù)據(jù)抽象

數(shù)據(jù)抽象可以將類的接口和實(shí)現(xiàn)分開。C語言中有struct來定義新的數(shù)據(jù)類型,但沒有實(shí)現(xiàn)數(shù)據(jù)類型和操作的綁定,要實(shí)現(xiàn)操作和數(shù)據(jù)類型的綁定,首先在傳入?yún)?shù)的時(shí)候,需要把struct的地址傳進(jìn)去,然后把所有的操作都變成函數(shù)指針存儲(chǔ)在結(jié)構(gòu)體中。以一個(gè)簡(jiǎn)單的類為例:

#ifndef _POINT_H_
#define _POINT_H_
typedef struct point* Point;
struct point{
    int x;
    int y;
    double (*distance)(Point p1);
    void (*print)(Point p);
};

double distance(Point p1);
Point create_point(int x,int y);
void print_point(Point p);

#endif
#include "point.h"
#include <stdlib.h>
#include <math.h>
#include <stdio.h>

void print_point(Point p){
    printf("x = %d, y = %d.\n",p->x,p->y);
}

double distance(Point p1){
    return sqrt(pow(p1->x,2) + pow(p1->y,2));
}

Point create_point(int x,int y){
    Point p = (Point)malloc(sizeof(struct point));
    p->x = x;
    p->y = y;
    p->distance = distance;
    p->print= print_point;
    return p;
}

int main(int argc, char const *argv[])
{
    Point p = create_point(1,1);
    p->print(p);
    printf("p distance = %f\n",p->distance(p));
    free(p);
    return 0;
}

這樣,對(duì)象的創(chuàng)建和方法的調(diào)用就有一點(diǎn)面向?qū)ο蟮母杏X了。

繼承

使用繼承,可以定義相似地的類型并對(duì)其關(guān)系建模。繼承就是對(duì)類的擴(kuò)展,為了能夠?qū)崿F(xiàn)兼容,派生的類必須有基類的所有成員和函數(shù)。然后可以在其基礎(chǔ)上增加一些功能,也可以改變?cè)械墓δ?。這里我簡(jiǎn)單的把基類的函數(shù)指針和成員放在派生類的前面。

#ifndef _CIRCLE_H_
#define _CIRCLE_H_
#include "point.h"
typedef struct circle* Circle;
struct circle{
    int x;
    int y;
    double (*distance)(Point p1);
    void (*print)(Circle c);
    int r;
    double (*area)(Circle c);    
};
Circle create_circle(int x,int y,int r);
double area(Circle c);

#endif
#include "circle.h"

void print_circle(Circle c){
    printf("x = %d, y = %d, r = %d.\n",c->x,c->y,c->r);
}

Circle create_circle(int x,int y,int r){
    Circle c = (Point)malloc(sizeof(struct circle));
    c->x = x;
    c->y = y;
    c->distance = distance;
    c->print = print_circle;
    c->r = r;
    c->area = area;
    return c;
}

double area(Circle c){
    return 3.14 * c->r * c->r;
}

int main(int argc, char const *argv[])
{
    Circle c = create_circle(1,1,2);
    printf("c distance = %f\n",c->distance(c));
    c->print(c);
    printf("c area = %f\n",c->area(c));
    return 0;
}

這里可以發(fā)現(xiàn),把point的成員放在前面,然后在初始化的時(shí)候,將函數(shù)指針賦值為point的函數(shù)地址,如果覆寫了,就改為改過之后的函數(shù)地址。可以發(fā)現(xiàn),能夠調(diào)用原來的函數(shù),也能夠調(diào)用新增的函數(shù)。

動(dòng)態(tài)綁定

動(dòng)態(tài)綁定,可以在一定程度上忽略相似類型的區(qū)別,而以統(tǒng)一的方式使用它們的對(duì)象??聪旅嬉粋€(gè)例子:

int main(int argc, char const *argv[])
{
    Circle c = create_circle(1,1,2);
    Point p = (Point)c;
    p->print(p);
    printf("p distace = %f\n",p->distance(p));
    return 0;
}

可以發(fā)現(xiàn),可以把Circle轉(zhuǎn)化為Point,并且可以正常的調(diào)用Point的方法。這里其實(shí)很簡(jiǎn)單,強(qiáng)制裝換之后,其實(shí)和沒有裝換是沒太大區(qū)別的,除了不能訪問其擴(kuò)展的成員。其實(shí)動(dòng)態(tài)綁定不在調(diào)用的時(shí)候,而在初始化的時(shí)候,print函數(shù)在初始化的時(shí)候就變成了新的地址,所以這里調(diào)用的時(shí)候,會(huì)使用Circle的函數(shù)。

總結(jié)

最近在看《深度探索C++對(duì)象模型》,一方面感覺C++編譯器的實(shí)現(xiàn)確實(shí)很巧妙,一方面又感覺C語言確實(shí)小巧精悍,即使不用C++,C語言本身也可以實(shí)現(xiàn)面向?qū)ο蟮臇|西。所以寫了這一篇筆記,加深一下自己對(duì)面向?qū)ο蟮睦斫?。個(gè)人水平有限,舉的例子也許有一些問題,望大家見諒。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容