C++学习笔记:(七)C语言实现面向对象编程

面试官:CC++有什么不同?

应聘者:一个是面向过程,一个是面向对象。

这样的答案在我看是不完全正确,因为面向过程编程和面向对象编程是编程思想,C++可以用面向过程的思想编程,同样,C语言也可以用面向对象的思想编程。可能很少有人想过用C语言实现面向对象编程(真的麻烦,感觉就是吃力不讨好),但是,通过这样的尝试,可以使我们的学习过程更有意思。也能通过用C语言实现面向对象编程来深化对封装、继承、多态的理解(这是我个人的感觉)。以下的例子可能过于简单或不够全面(只实现了一部分),如果想再深入研究,建议上网百度相关的知识。

在学习如何使用C语言完成面向对象编程之前,先来看函数指针的用法。

#include 
char (*p)(int);
char Fun(int a)
{
    return a;
}

int main()
{
    p = Fun;
    printf("%c\n",(*p)(75));
    return 0;
}

复习了函数指针,接下来尝试用C语言中实现C++中的类,类似于:

class Asd
{
    public:
    int a,b;
    int finda(){return a;}
    int findb(){return b;}
    int ab(){return a+b;}
};

具体实现如下:

#include 
#include 
struct Asd;
struct Asd_option//Asd类的函数成员
{
    int (*get_a)(struct Asd*);
    int (*get_b)(struct Asd*);
    int (*ab)(struct Asd*);
};

typedef struct Asd//Asd类
{
    int a;//公有数据成员 
    int b;//公有数据成员
    struct Asd_option *a_option;//函数指针,指向的是操作
}Asd;

int finda(struct Asd *s)//具体操作
{
    return s->a;
}
int findb(struct Asd *s)
{
    return s->b;
}
int findab(struct Asd *s)
{
    return (s->a)+(s->b);
}

struct Asd_option qwe_option =
{
    finda,
    findb,
    findab
};//函数指针赋值

struct Asd Asd_create(int x, int y)//Asd类的构造函数
{
    struct Asd asd;
    asd.a = x;
    asd.b = y;
    asd.a_option = &qwe_option;
    return asd;
}

int main()
{
    Asd a = Asd_create(1,2);
    int x = a.a_option->get_a(&a);
    int y = a.a_option->get_b(&a);
    int z = a.a_option->ab(&a);
    printf("X:[%d] Y:[%d] Z:[%d]\n", x,y,z);
    printf("Asd_a:[%d]\n", a.a);
    return 0;
}

C语言中,结构体就能完成简单的封装。因为结构体中是不能像C++类那样声明函数成员,所以要使用函数指针完成这一部分的功能。

struct Asd_option qwe_option =
{
    finda,
    findb,
    findab
}; 

这就是通过结构体对函数指针赋值。这样使得Asd类既有数据成员,又有函数成员。

上面的例子完成了最简单的封装,而且数据成员都是公有的,接下来实现保护或私有数据成员,类似于:

class Asd
{
private:
    int x,y;
public:
    int a,b;
    int findx(){return x;}
    int findy(){return y;}
    int xy(){return x+y;}
};
#include 
#include 
struct Asd;
struct Asd_option//可以设为保护成员也可以设为私有成员
{
    int x;
    int y;
    int (*get_x)(struct Asd*);
    int (*get_y)(struct Asd*);
    int (*xy)(struct Asd*);
};

typedef struct Asd//Asd类
{
    int a;
    int b;
    struct Asd_option *a_option;//函数指针
}Asd;

int findx(struct Asd *s)//具体操作
{
    return s->a_option->x;
}
int findy(struct Asd *s)
{
    return s->a_option->y;
}
int findxy(struct Asd *s)
{
    return (s->a_option->x)+(s->a_option->y);
}

struct Asd_option qwe_option =
{
    0,
    0,
    findx,
    findy,
    findxy
};//函数指针赋值

Asd Asd_create(int m, int n)//Asd类的构造函数
{
    struct Asd asd;
    asd.a = 3;
    asd.b = 4;
    asd.a_option = &qwe_option;
    asd.a_option->x = m;
    asd.a_option->y = n;
    return asd;
}

int main()
{
    Asd a = Asd_create(1,2);
    int x = a.a_option->get_x(&a);
    int y = a.a_option->get_y(&a);
    int z = a.a_option->xy(&a);
    printf("X:[%d] Y:[%d] Z:[%d]\n", x,y,z);
    printf("Asd_a:[%d]\n", a.a);
    printf("Asd_b:[%d]\n", a.b);
    //printf("Asd_x:[%d]\n", a.x);     
    //printf("Asd_y:[%d]\n", a.y);     //x,y保护(或私有)数据成员,不能直接访问
    return 0;
}

接下来实现简单的重载多态:

#include 
#include 
typedef struct intasd
{
    int a;
    int b;
}Int_asd;

typedef struct floatasd
{
    float x;
    float y;
}Float_asd;

typedef void* (*Addfunction)(void*); //typedef定义函数指针的语法:typedef 返回类型 (*指针名)(参数表)

void* intadd(void *asd)
{
    Int_asd *s = (Int_asd*)asd;
    int amount = s->a + s->b;
    printf("Result: = [%d]\n", amount) ;
}

void* floatadd(void *asd)
{
    Float_asd *s = (Float_asd*)asd;
    float amount = s->x + s->y;
    printf("Result: = [%f]\n", amount) ;
}

void* Add(Addfunction f, void *asd)
{
    return f(asd);
}

int main()
{
    Int_asd x = {1, 2};
    Float_asd y = {1.1, 2.2};
    Add(intadd, &x);
    Add(floatadd, &y);
    return 0;
}

实现继承和包含多态:

#include 
#include 
#include 
struct Shape;
struct Shape_option
{
    float (*area)(struct Shape*);/*返回几何体的面积*/
    int (*perimeter)(struct Shape*);/*返回几何体的周长*/
};

typedef struct Shape //基类
{
    char* Shape_name;
    struct Shape_option *Shape_ops; /*虚函数,功能由子类实现*/
}Shape;

float Shape_area(struct Shape* s)/*求形状面积*/
{
    return s->Shape_ops->area(s);
}

int Shape_perimeter(struct Shape* s) /*求周长*/
{
    return s->Shape_ops->perimeter(s);
}

typedef struct triangle/*三角形类*/
{
    Shape Base;//公有继承
    int a;
    int b;
    int c;
}Triangle;

float Triangle_area(struct Shape* s)/*三角形面积,用海伦公式*/
{
    Triangle *t = (Triangle*)s;
    int x = t->a;
    int y = t->b;
    int z = t->c;
    float p = (x+y+z)/2;
    return sqrt(p*(p-x)*(p-y)*(p-z));
}

int Triangle_perimeter(struct Shape* s)/*三角形周长*/
{
    Triangle* t = (Triangle*)s;
    int x = t->a;
    int y = t->b;
    int z = t->c;
    return x+y+z;
}

struct Shape_option triangle_ops =/*对父类虚函数的实现*/
{
    Triangle_area,
    Triangle_perimeter
};

Triangle* Triangle_create(int x,int y,int z)/*三角形构造函数*/
{
    Triangle* ret = (Triangle*)malloc(sizeof (*ret));
    ret->Base.Shape_name = "triangle";
    ret->Base.Shape_ops = &triangle_ops;
    ret->a = x;
    ret->b = y;
    ret->c = z;
    return ret;
}

typedef struct rectangle/*矩形类*/
{
    Shape Base;//公有继承
    int width;
    int height;
}Rectangle;


float Rectangle_area(struct Shape* s)/*矩形函数成员*/
{
    Rectangle* r = (Rectangle*)s;
    return r->width * r->height;
}

int Rectangle_perimeter(struct Shape* s)/*矩形函数成员*/
{
    Rectangle* r = (Rectangle*)s;
    return (r->width+r->height)*2;
}

struct Shape_option rectangle_ops =/*对父类虚函数的实现*/
{
    Rectangle_area,
    Rectangle_perimeter
};

Rectangle* Rectangle_create(int width, int height)/*矩形构造函数*/
{
    Rectangle* ret = (Rectangle*)malloc(sizeof(*ret));
    ret->Base.Shape_name = "rectangle";
    ret->Base.Shape_ops = &rectangle_ops;
    ret->height = height;
    ret->width = width;
    return ret;
}

int main()
{
    Shape *s[4];
    s[0] = (Shape*)Triangle_create(5,5,4);
    s[1] = (Shape*)Triangle_create(3,4,5);
    s[2] = (Shape*)Rectangle_create(10,12);
    s[3] = (Shape*)Rectangle_create(5,8);
    int i=0;
    for(i=0 ;i<4 ;i++)
    {
        float area = Shape_area(s[i]);
        int perimeter = Shape_perimeter(s[i]);
        char *name = s[i]->Shape_name;
        printf("name:%s ,area:%.2f ,perimeter:%d\n",name,area,perimeter);
    }
    return 0;
}

Shape是基类,Triangle类继承基类Shape,并新增数据成员abc,实现简单的继承。上述例子中,子类对父类虚函数进行实现,实现了包含重载。虽然上面的结果可能不能像C++所展示的那样,但是思想上是面向对象的。

运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义。实际上,C++(包括C语言)运算符已经被重载。例如,将*运算符用于地址,将得到存储在这个地址中的值;但将它用于两个数字时,得到的将是他们的乘积。

参考:http://blog.chinaunix.net/uid-26921272-id-3360269.html

你可能感兴趣的:(C/C++)