zoukankan      html  css  js  c++  java
  • 基于C语言的面向对象编程

    嵌入式软件开发中,虽然很多的开发工具已经支持C++的开发,但是因为有时考虑运行效率和编程习惯,还是有很多人喜欢用C来开发嵌入式软件。Miro Samek说:“我在开发现场发现,很多嵌入式软件开发者(绝大多数是电子工程师)都有工作背景而且他们常常不喜欢用C++。”【1】

    面向对象编程(OOP)是一种方法,而不依赖于某特定语言。一般认为,OOP只能使用面向对象的语言,如Smalltalk、C++或Java等固有支持OOP的语言。但是,OOP并不依赖于特殊的语言,只要实现了OOP的封装、继承和多态性这三大基本特性,使用非固有支持面向对象的语言,也可以进行面向对象的编程。

    面向对象编程方法的三大基本特性是:

    • 封装性---封装数据(属性)与函数(方法)到类中的能力;
    • 继承性---基于已有的类定义新类的能力;
    • 多态性---在运行时具有一致接口的对象相互替换的能力。

    虽然这些特性与面向对象语言有关,但几乎可以用任何语言实现面向对象的这三大基本特性,包括C语言和汇编语言等。事实上,不管实现语言为何,任何大的软件系统几乎都会以某种形式使用抽象(封装)、继承或多态性。

    1.C语言的封装

    1.1 封装的本质

    在C++中,一个类中包括属性和方法,声明一个类例子如下:

    class A {
      int n;                 //属性
      A();                   //构造函数
      void function1(int x){...}; //方法
    }
    

    在C++中,用A生成两个对象a1和a2时,如下:

    A a1 = new A();
    A a2 = new A();
    

    对于非模板类A,在内存中,对所有的对象,方法function1只有一个拷贝,而对每个对象,都有自己独立的一份属性拷贝,也就是有多个属性拷贝,所谓创建一个对象,也就是创建一套属性。

    调用a1.function1()和a2.function1()时,每个对象使用自己的属性n1和n2,而方法代码在内存中是同一套。这就相当于调用functin1(n1,x)和function1(n2,x)。

    在C语言实现中,把所有的属性放到一个结构中,所有方法中第一个参数用一个指向自己属性结构的一个指针me, 如下:
    function1(struct *me, ...);
    这个方法对所有对象有用,具体对哪个对象的属性操作,可以用me来区分。

    1.2 具体例子

    生成两个文件person.h和person.c,定义一个Person结构类型(也就是类名称),把属性放到结构中方法中的第一个参数me是Person的引用指针

    pers1.2on.h文件:
    在头文件中以结构定义类成员属性,声明构造方法和析构方法,声明public方法。

    #ifndef PERSON_H
    #define PERSON_H
    
        /*1.定义类成员属性(没有隐藏)*/
        typedef struct PersonTag {
            String name__; /*属性*/
            uint8_t age__; /*属性*/
        }Person;  
          
        /*2.声明构造和析构函数*/
        void Person_Ctor(Person *me, uint8_t age);/*第一个参数指向属性*/
        void Person_Xtor(Person *me);/*第一个参数指向属性*/
    
        
        /*3.声明public方法*/
        void Person_setName(Person *me, String name);/*第一个参数指向属性*/
        String Person_getName(Person *me);/*第一个参数指向属性*/
        
        /*4.声明private方法(要在person.c文件中声明)*/ 
          
    #endif
    

    person.c文件:
    在.c文件中声明private方法,并实现所有的方法。

    #include "person.h"
    
    /*1.声明private方法, 用static修饰*/
    static void Person_setAge(Person *me, uint8_t age);/*第一个参数指向属性*/
    static uint8_t Person_getAge(Person *me);/*第一个参数指向属性*/
    
    /*2.实现构造和析构函数*/
    void Person_Ctor(Person *me, uint8_t age) {
        me->age__ = age;
    }
    void Person_Xtor(Person *me) {
        ...
    }
    
    /*3.实现public方法*/
    void Person_setName(Person *me, String name) {
        me->name__ = name;
    }
    String Person_getName(Person *me) {
        return me->name__;
    }
    
    /*4.实现private方法*/
    void Person_setAge(Person *me, uint8_t age) {
        me->age__ = age;
    }
    uint8_t Person_getAge(Person *me) {
        return me->age__;
    }
    

    app.c中使用Person类:

    #include "person.h"  /*包含头*/
    void main() {
        String tmp;
        Person l_ps1; /*创建一个实例,实际就是一个属性*/
        Person l_ps2; /*创建另一个实例,实际就是另一个属性*/
        
        Person_Ctor(l_ps1, 30);      /*显式调用构造函数*/
        Person_setName(l_ps1,"张三"); /*使用其public方法*/
        tmp = Person_getName(l_ps1); /*使用其public方法*/
        
        Person_Ctor(l_ps2, 30);       /*使用其public方法*/
        Person_setName(l_ps2, "李四"); /*使用其public方法*/
        tmp = Person_getName(l_ps2);  /*使用其public方法*/
    }
    

    2.C语言的继承

    Student继承自Person, 继承类属性结构的第一个参数指向父类属性,这样可以满足Liskov替换原则

    student.h文件:
    在头文件中以结构定义类成员属性,并声明构造、析构函数和public方法。

    #ifndef STUDENT_H
    #define STUDENT_H
    #include "person.h"  /*包含父类头*/
    
        /*1.定义类属性(没有隐藏)*/
        typedef struct StudentTag {
            Person super;   /*第一个参数指向父类Person,继承父类属性*/
            uint8_t code__; /*子类添加的属性*/
        }Student;  
          
        /*2.声明构造和析构方法*/
        void Student_Ctor(Student *me, uint8_t code);
        void Student_Xtor(Student *me);
        
        /*3.声明public方法*/
        void Student_setCode(Student *me, uint8_t code);
        uint8_t Student_getCode(Student *me);
        
        /*4.声明private方法(在.c文件中声明)*/ 
          
    #endif
    

    student.c文件:
    在.c文件中声明private方法,实现所有的构造方法和析构方法,实现所有的public和private方法。

    #include "student.h"
    
    /*1.声明private方法*/
    static void XXX(Student *me, ...);
     
    
    /*2.构造和析构方法实现*/
    void Student_Ctor(Student *me, String name, uint8_t code) {
        Person_Ctor((Person*)me, name);/*先调用父类构造函数*/
        me->code__ = code;
    }
    void Person_Xtor(Person *me) {
        ...
    }
    
    /*3.public方法实现*/
    void Student_setCode(Student *me, uint8_t code) {
        me->code__ = code;
    }
     
    

    app.c中使用Student类:

    #include "Student.h"  /*包含头*/
    void main() {
        String tmp;
        Student l_st1; /*创建一个实例,实际就是一个属性*/
        Student l_st2; /*创建另一个实例,实际就是另一个属性*/
        
        Student_Ctor(l_st1, "张三, 25);  /*显式调用构造函数*/
        Student_setCode(l_st1, 30); //使用其public方法
        tmp = Student_getCode(l_st1); //使用其public方法
    }
    

    3.C语言的多态性

    利用C语言的万能指针void *p可以实现多态。略。

    4.总结

    用C语言可以实现面向对象的三大特性,适合于嵌入式系统的编程,QP的C版本就是这样实现的。现在很多的开源软件,包括postgreSQL、GObject等都采用C语言实现面向对象的方法。采用这个方法,使程序具有更好的可读性、可扩展性,同时保持了C语言的高效性。

  • 相关阅读:
    Sql优化(二) 快速计算Distinct Count
    Minor GC和Full GC区别(转)
    对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法
    2017/6/29杂记
    java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总
    ThreadLocal的设计理念与作用
    2017/6/28杂记
    关于hashmap 与concurrentHashMap
    2017/6/27杂记
    深入理解java异常处理机制
  • 原文地址:https://www.cnblogs.com/hyper99/p/ji-yuC-yu-yan-de-mian-xiang-dui-xiang-bian-cheng.html
Copyright © 2011-2022 走看看