OOPC C语言面向对象

1. C语言中的面向对象

​ 我在工作之前,学习的是C++和python这样的语言,工作以后虽然也还用这两种语言开发一些程序,但是嵌入式开发中主要使用的是C语言,我常常在想C语言和C++的区别,C++可以分为四大部分,C语言、面向对象、泛型编程、STL,这四个主要模块,再加上大量的细小的特性构成了如今的C++,在这里C++的函数重载特性导致了和C语言的兼容出现问题,给C和C++的混合编程带来了一些麻烦。

​ 本文想讨论C和C++在面向对象上的使用,从软件工程的发展历史上来看,面向对象就是将一些数据给隐藏起来,使用对外函数来访问这些数据,C语言不是为面向对象设计的语言,但是面向对象作为一种编程思想和模式,并不为某种语言所特有。也是说C语言同样可以通过一些手段实现面向对象,只是想比于C++这种为面向对象设计的语言,多少有些繁琐。在实际开发和研究过程种,我对于C语言的面向对象有了一些认识和感悟。本文将重点讲讲这一部分。

​ 面向对象作为一种编程思想,为软件开发带来根本性的指导,所谓的设计模式和设计原则都是围绕着面向对象展开的,那么面向对象的好处是什么呢,在软件规模越来越大的时候,面向过程的编程方式不再适合整体的软件架构,唯有对软件的行为的约束和限制,才能使得软件更加健康的发展,所以面向对象其实是对软件行为的约束,并未扩展软件行为的能力,这就是面向对象的封装特性,而继承,则是代码的复用,在C语言中,代码的复用通过函数即可实现,多态的意义则是延迟变化,将行为在软件中动态调用,这也就是函数指针的功能,其实所谓的多态,本质的实现逻辑就是函数指针,只是C++直接使用函数指针过于危险,将这一部分在编译器中实现,编码时并不感知指针的存在。

​ C语言面向对象的问题在于并没有统一的格式,由于C语言的设计中,并没有考虑面向对象,C语言的封装和多态都需要靠指针来实现。而继承是使用父类的结构体,而且,封装的程度也随着各个开发者的习惯而定,这就使得C语言面向对象的形式表现较为,并无统一格式。

​ C语言面向对象其实也有一定的优势,就是函数指针,原本在C++中被限制的行为,在C语言中可以被突破,比如virtual修饰的函数才能被覆盖,在C语言中函数都是通过指针存放在结构体中的,所以就出现没有不可替换的函数。当然这是优点,也是缺点,优点是有更多的可能性,缺点是打破原则,对于大的框架而言带来一些不必要的麻烦。

​ C语言为什么要面向对象,面向对象费时费力,往往我们要实现一个功能,直接写个函数,然后找个地方调用就好了,在代码量较小时还好,软件功能越来越多,就出现了一些问题,有些没有统一的接口,导致函数的访问在软件内跳来跳去,软件耦合性增加,修改维护时,牵一发而动全身。所以面向对象是为了架构整洁,当然并不是说不用面向对象就实现不了整洁的架构,只是面向对象对访问做出了限制,使得程序的健壮性增加。在拥有面向对象的特性后,设计模式和设计原则就排上了用场,。

​ 下面就说说我所认为的C语言面向对象应该的样子:

  • 首先就是简洁,C语言实现有限的面向对象即可,我并不希望C语言能够完全实现C++那样的特性,当然麻烦一些,也是可以做到大部分的,如果说软件整体架构对面向对象非常依赖,那么我建议使用其他编程语言,C语言在实现面向对象时,本身就有这个负担,相比于其他语言开发上会有更大的压力,当然非做不可,也不是不行,小心谨慎,多写测试用例。所以我认为C语言实现有限的面向对象即可,强多态,中封装,弱继承,或者封装和继承可以调换一下优先级,毕竟实现每个特性是有代价的,在C语言中就是代码变得复杂臃肿。
  • 构造函数在struct之外,析构函数在struct之内,在调用构造函数的时候,对象还没有创建,所以构造函数放在结构体内部的意义不大,但是析构函数是可以在结构体内的,所以放在内部是没什么问题。整体类的对外呈现就是构造函数+类本身。
  • 在继承和接口上,建议使用,单继承或者单接口,如果需要多接口,较为繁琐,调用非第一接口时需要将指针的偏移,不太推荐。
  • 若是注重多态,可以在子类构造函数中,直接返回父类指针。

2. Demo

// Printer.h
#ifndef __PRINTER_H
#define __PRINTER_H

typedef struct Printer_t Printer;
struct Printer_t {
    char name[20];
    void (*Print)(Printer *this, char *buf);
    void (*Delete)(Printer *this);
};

typedef struct AutoPrinter_t AutoPrinter;
struct AutoPrinter_t {
    Printer base;
};

Printer *AutoPrinterCreator(char *devName);

typedef struct PaperPrinter_t PaperPrinter;
struct PaperPrinter_t {
    Printer base;
    int num;
};

Printer *PaperPrinterCreator(char *devName, int n);

#endif


// printer.c
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include "Printer.h"
#include "string.h"

void AutoPrint(Printer *this, char *buf)
{
    printf("type:auto [%s]: %s\n", this->name, buf);
}

void AutoPrinterDestructor(Printer *this)
{
    AutoPrinter *me = (AutoPrinter *)this;
    free(me);
    printf("AutoPrinter Del\n");
}

Printer *AutoPrinterCreator(char *devName)
{
    AutoPrinter *me = (AutoPrinter *)malloc(sizeof(AutoPrinter));
    memcpy(me->base.name, devName, 20);
    me->base.Print = AutoPrint;
    me->base.Delete = AutoPrinterDestructor;
    return (Printer *)me;
}

void PaperPrint(Printer *this, char *buf)
{
    PaperPrinter *me = (PaperPrinter *)this;
    printf("type:paper paperNum:%d [%s]: %s\n", me->num, this->name, buf);
}

void PaperPrinterDestructor(Printer *this)
{
    PaperPrinter *me = (PaperPrinter *)this;
    free(me);
    printf("PaperPrinter Del\n");
}

Printer *PaperPrinterCreator(char *devName, int n)
{
    PaperPrinter *me = (PaperPrinter *)malloc(sizeof(PaperPrinter));
    memcpy(me->base.name, devName, 20);
    me->base.Print = PaperPrint;
    me->base.Delete = PaperPrinterDestructor;
    me->num = n;
    return (Printer *)me;
}


// main.c
#include <stdio.h>
#include <stdint.h>
#include "Printer.h"

int main()
{
    Printer *pAuto1 = AutoPrinterCreator("auto1");
    pAuto1->Print(pAuto1, "i am auto1");
    pAuto1->Delete(pAuto1);
    Printer *pAuto2 = AutoPrinterCreator("auto2");
    pAuto2->Print(pAuto2, "i am auto2");
    pAuto2->Delete(pAuto2);

    Printer *pPaper1 = PaperPrinterCreator("paper1", 15);
    pPaper1->Print(pPaper1, "i am PaperPrinter p1");
    pPaper1->Delete(pPaper1);
    Printer *pPaper2 = PaperPrinterCreator("paper2", 20);
    pPaper2->Print(pPaper2, "i am PaperPrinter p2");
    pPaper2->Delete(pPaper2);
    return 0;
}

3. 总结

​ C语言在程序开发过程中,在大型程序开发过程中,往往会考虑使用面向对象,面向对象的应用,规范软件结构程序,得益于设计原则的应用,使得软件的各个模块能够做到一定程度上的结构,结构体的封装也使得程序,在一定程度上的内聚,在软件的扩展和可维护性上都相当程度的提升,最为关键的是,我们有了驾驭大型软件架构的能力。

参考资料

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《UML与面向对象分析与设计精讲》是一本系统介绍UML和面向对象分析与设计的重要书籍。UML是一种用于构建、可视化和编写软件蓝图的标准化语言面向对象分析与设计是以对象为中心进行软件开发的方法。 该书主要分为四个方面的内容,分别是UML基础知识、UML的建模方法与技术、面向对象分析与设计概述和面向对象分析与设计的详细过程。 在UML基础知识部分,该书详细介绍了UML的发展背景、核心概念、基本建模元素和建模视图等内容。读者可以通过学习这些知识来了解UML的基本概念和使用方法。 而在UML的建模方法与技术部分,该书主要介绍了UML的各种建模图,包括用例图、类图、对象图、活动图、顺序图和状态图等。这些图可以帮助开发者更好地理解软件系统的需求和结构。 面向对象分析与设计部分,该书详细介绍了面向对象分析与设计的概念、原则和方法。通过学习这个部分,读者可以了解如何从需求分析到软件设计的整个过程,如何识别实体、定义类和设计系统架构。 最后,该书对面向对象分析与设计的详细过程进行了深入剖析,包括需求分析、领域建模、用例建模、系统设计、类设计、接口设计等。通过对这些过程的学习,读者可以掌握实际的软件开发技巧和方法。 总的来说,《UML与面向对象分析与设计精讲》是一本很好的用于学习UML和面向对象分析与设计的书籍,对于从事嵌入式C语言开发的人员来说,学习并掌握这些知识,可以帮助他们更好地进行软件开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值