C语言-----如何面向对象编程

1、引语

  • 编程语言发展到今天,已经有相当多种了,有些甚至都没有听说过和接触过。对于一个程序员来说,C语言都是基础,C语言是一个面向过程的程序设计语言,那么如何使用C语言来写出面向对象的程序呢?

  • 面向对象编程的三个基本特征是封装、继承和多态。

  • 先使用一个C++的例子,然后把例子转成C语言。

////////////////////////////Object.h/////////////////////////

//基类
class Object
{
public:
    Object(double h);
    ~Object(){}
    virtual double calcuArae() = 0; //计算表面积
    virtual double calcuVolume() = 0;//计算体积
    //有一个共同的属性
    double height;
};

//圆柱体
class Cylinder :public Object
{
public:
    Cylinder(double h,double r);
    ~Cylinder(){}
    virtual double calcuArae();
    virtual double calcuVolume();
    double radius;
};

//长方体
class Cuboid :public Object
{
public:
    Cuboid(double h,double w,double l);
    ~Cuboid(){}
    virtual double calcuArae();
    virtual double calcuVolume();
    double weith;
    double length;
};

实现:

///////////////////////////Object.cpp///////////////////////
//基类构造函数
Object::Object(double h)
    :height(h)
{
}
/////////////////////////////////////////////////////////
Cylinder::Cylinder(double h, double r)
    :Object(h)
    ,radius(r)
{

}
double Cylinder::calcuArae()
{
    return 2*PI*radius*radius + 2*PI*radius*height;
}
double Cylinder::calcuVolume()
{
    return  (PI*(radius*radius)/4)*height;
}
/////////////////////////////////////////////////////////
Cuboid::Cuboid(double h, double w, double l)
    :Object(h)
    ,weith(w)
    ,length(l)
{
}
double Cuboid::calcuArae()
{
    return length*weith*height;
}
double Cuboid::calcuVolume()
{
    return 2*(length*weith+weith*height+length*height);
}

多态:

    QVector<Object*> vec;
    vec<< new Cylinder(2,3);
    vec<< new Cuboid(2,3,4);

    for(int i = 0 ; i < vec.size();i++)
    {
        qDebug()<<vec.at(i)->calcuArae();
        qDebug()<<vec.at(i)->calcuVolume();
    }

C++的多态是依靠虚函数来实现的。

2、封装

在C++中使用class来封装数据与方法的 在C语言中使用的struct来封装数据与方法的,在标准的C运行库里一组函数fopen(), fclose(),fread(), and fwrite() ,就是在操作FILE结构的,每个函数都会传入一个FILE的指针。

封装比较好办

//抽象对象
typedef struct 
{
    int16_t x;  
    int16_t y;  
} Shape;

//构造函数
Shape *Shape_new(int16_t x, int16_t y)
{
    Shape * obj = (Shape*)malloc(sizeof(Shape));
    obj->x = x;
    obj->y = y;
    return obj;
}
//方法
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy)
{
    me->x += dx;
    me->y += dy;
}

3、继承

C语言里的继承有点像C++的组合,子类包函父类的对象。

//具体对象
typedef struct 
{
    Shape super; //这里一定要放在最前面
    uint16_t width;
    uint16_t height;
} Rectangle;

//构造函数
Rectangle*Rectangle_new(int16_t x, int16_t y,uint16_t width, uint16_t height)
{
    Rectangle* r = (Rectangle*)malloc(sizeof(Rectangle));
    r->super.x = x;
    r->super.y = y;
    r->width = width;
    r->height = height;
    return r;
}
//方法,使用基类的方法

应用:

Rectangle* r1 = Rectangle_new(1,1,2,3);
Shape_moveBy((Shape *)r1, -2, 3);//向上类型转换,upcasting在C++里是安全的

4、多态

  • 多态的实现就是建立一张虚表,然后实现后绑定。对于C语言来说就是使用函数指针的方法。

先封装:

//基类
typedef struct
{
    struct ObjectVtbl const *vptr;//虚表,这个也得放在最前面
    double height;
}Object;

//虚表类
struct ObjectVtbl
{
    double (*area)(Object * const o);
    double (*volume)(Object * const o);
};

//Cylinder子类
typedef struct
{
    Object super;
    double radius;
}Cylinder;

//Cuboid子类
typedef struct
{
    Object super;
    double width;
    double length;
}Cuboid;

再把所有的方法实现了:
这些方法只在模块内使用不expouse给用户

static double cylinder_area(Object * const o)
{
    Cylinder * const me = (Cylinder *)o;

    double r = (uint)me->radius;
    double h = (uint)o->height;

    return 2*PI*r*r + 2*PI*r*h;
}
static double cylinder_volume(Object * const o)
{
    Cylinder * const me = (Cylinder *)o;

    double r = (uint)me->radius;
    double h = (uint)o->height;

    return  (PI*(r*r)/4)*h;
}
/////////////////////////////////////////////////////////////
static double cuboid_volume(Object * const o)
{
    Cuboid * const me = (Cuboid *)o;

    double w = (uint)me->width;
    double h = (uint)o->height;
    double l = (uint)me->length;

    return l*w*h;
}

static double cuboid_area(Object * const o)
{
    Cuboid * const me = (Cuboid *)o;

    double w = (uint)me->width;
    double h = (uint)o->height;
    double l = (uint)me->length;

    return 2*(l*w+w*h+l*h);
}

再把构造函数给实现了:

Cuboid * new_Cuboid(double l,double w,double h)
{
    //这里要使用static、const,因为所有的实例都使用同一套函数
    //而且这里应该要在rom上分配空间
    static struct ObjectVtbl const vtbl = { &cuboid_area,
                                            &cuboid_volume,
                                            };
    Cuboid * c = (Cuboid *)malloc(sizeof(Cuboid));
    c->super.vptr = &vtbl;
    c->super.height = h;
    c->length = l;
    c->width = w;

    return c;
}

Cylinder * new_Cylinder(double r,double h)
{
    static struct ObjectVtbl const vtbl = { &cylinder_area,
                                            &cylinder_volume,
                                            };
    Cylinder * c = (Cylinder *)malloc(sizeof(Cylinder));
    c->super.vptr = &vtbl;
    c->super.height = h;

    c->radius = r;

    return c;
}

最后把要后绑定的方法实现了:


static double calcu_area(Object * const o)
{
    return (*o->vptr->area)(o);
}

static double calcu_volume(Object * const o)
{
    return (*o->vptr->volume)(o);
}

使用:

    Cylinder *cylinder = new_Cylinder(2,6);
    Cuboid *cuboid = new_Cuboid(2,6,5);

    Object *table[2];
    table[0] = (Object *)cylinder;
    table[1] = (Object *)cuboid;

    for(int i = 0 ; i < 2 ;i++)
    {
        qDebug()<<calcu_area(table[i]);
        qDebug()<<calcu_volume(table[i]);
    }

5、总结

  1. Object Oriented Programming 是一种设计方法而非一种语言
  2. 封装与继承,C语言可以轻松的handle,但是多态的话相对复杂,而且没有带来任何性能上的提升。
  3. 如果是写框架之类的可以考虑使用多态来隐藏细节,一般的应用不要使用。

6、参考

https://www.cs.rit.edu/~ats/books/ooc.pdf
https://www.state-machine.com/doc/AN_OOP_in_C.pdf
https://www.youtube.com/watch?v=d5k_HBPFm0M
https://stackoverflow.com/questions/415452/object-orientation-in-c
http://ldeniau.web.cern.ch/ldeniau/html/oopc.html
https://sourceforge.net/projects/lwoopc/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值