【UML+OOPC嵌入式C语言开发】面向对象开发实战开发之书籍与作者信息存储

  • @[toc]

    论述

    在某次需求中,如果书籍A有两个属性------名字与编号,当然了每本书籍还会对应一个作者;同时呢,每个作者还会有自己的属性,即名字与作者电话。(这里只是一个假设,实际中书籍与书籍作者不可能只含有这些属性😅)   这样,那么就会有两种实现方式:

    • 方式一:只设计一个类,类中的属性有:书籍名字、书籍编号、作者名字、作者电话;
    • 方式二:两个类,书籍类含有三个属性:名字、编号、作者类指针,作者类也含有两个属性,即名字与电话,那么这两个类。   上述的两种方式,其实各有优劣:
    • 当需要存储的每本书籍的作者都不想同时,使用方式一较为方便。从类的操作上来看,类的初始化是需要一次;
    • 当需要存储的书籍的作者同时拥有两本或两本以上的书籍时,使用方式二较为方便,从作者的信息存储来看,使用方式二作者信息不需要多次存储,而使用方式一时需要多次存储作者信息。   也就是说,这两者的最终结构会如下图:   上面是在讨论类的设计,但实际编程中还需要考虑数据存储的方式,即使用链表存储还是使用使用数组存储。两者的差别不大, 同样的在结构上也各有优劣,使用数组存储时,增加、查找比较方便;而使用链表存储时,删除、插入比较方便。

    代码实现

    使用数组实现

    main.c文件

    c 复制代码
    #include "stdio.h"
    #include "book.h"
    #include "lw_oopc.h"
    
    int main(void)
    {
        char temp1[10],temp2[10];
        author*a[10] ;
        book*b[10];
        for(int i=0;i<10;++i)
        {
            // 作者初始化
            a[i] = (author*)author_new();
            sprintf(temp1,"a%d",i);
            sprintf(temp2,"t%d",i);
            a[i]->vInit(a[i],temp1,temp2);
    
            // 书籍初始化
            b[i] = (book*)book_new();
            sprintf(temp1,"bn%d",i);
            sprintf(temp2,"bt%d",i);
            b[i]->vSetNumberAndTile(b[i],temp1,temp2);
            b[i]->vSetAuthor(b[i],a[i]);
    
            // 显示
            b[i]->vDisplay(b[i]);
        }
    	return 0;
    }

    book.h文件

    c 复制代码
    #ifndef _BOOK_H
    #define _BOOK_H
    
    #include "lw_oopc.h"
    
    // 作者类
    CLASS (author)
    {
        void (*vInit) (void*,char*,char*);
        char* (*vGetName) (void*);
        char* (*vGetTelNo) (void*);
        char _name[14];
        char _telPhoto[20];
    };
    
    // 书籍类
    CLASS (book)
    {
        void (*vSetNumberAndTile) (void*,char*,char*);
        void (*vSetAuthor)  (void*,author*);
        void (*vDisplay) (void*);
        char _bookNo[20];
        char _bookTitle[20];
        author *_author;
    };
    #endif //_BOOK_H

    book.c文件

    c 复制代码
    #include "book.h"
    #include "string.h"
    #include "stdio.h"
    
    /************ 作者类 **********/
    
    // 初始化
    static void aInit(void*pointer,char*name,char*tel)
    {
        author*pthis = (author*)pointer;
        strcpy(pthis->_name,name);
        strcpy(pthis->_telPhoto,tel);
    }
    
    // 获取名字
    static char* aGetName(void*pointer)
    {
        author*pthis = (author*)pointer;
        return pthis->_name;
    }
    
    // 获取电话
    static char*aGetTel(void*pointer)
    {
        author*pthis = (author*)pointer;
        return pthis->_telPhoto;
    }
    CTOR(author)
        FUNCTION_SETTING(vInit,aInit);
        FUNCTION_SETTING(vGetTelNo,aGetTel);
        FUNCTION_SETTING(vGetName,aGetName);
    END_CTOR
    
    /********** 书籍类 *********/
    
    // 设置书籍的书籍号与名字
    static void bSetNumberAndTile(void*pointer,char*no,char*ti)
    {
        book* pthis = (book*)pointer;
        strcpy(pthis->_bookNo,no);
        strcpy(pthis->_bookTitle,ti);
    }
    
    // 设置作者
    static void bSetAuthor(void*pointer,author*myAuthor)
    {
        book*pthis = (book*)pointer;
        pthis->_author = myAuthor;
    }
    
    // 打印书籍信息
    static void bDisplay(void*poniter)
    {
        book *pthis = (book*)poniter;
        author*myAuthor = pthis->_author;
        printf("bookNumber:%s bookTitle:%s ",pthis->_bookNo,pthis->_bookTitle);
    
        printf("authorName:%s authorTel:%s\n",myAuthor->_name,myAuthor->_telPhoto);
    }
    
    CTOR (book)
        FUNCTION_SETTING(vSetAuthor,bSetAuthor);
        FUNCTION_SETTING(vSetNumberAndTile,bSetNumberAndTile);
        FUNCTION_SETTING(vDisplay,bDisplay);
    END_CTOR

    实验结果

    使用链表实现

    main.c

    c 复制代码
    #include "stdio.h"
    #include "book.h"
    #include "lw_oopc.h"
    
    int main(void)
    {
    	// 初始化链表头结点
        bookList*bookInfo = (bookList*)bookList_new();
        // 新增节点
        listBookNode*b1 = (listBookNode*)listBookNode_new();
        b1->vSet(b1,"C language","123123","zhoujie","19891890");
        bookInfo->vAdd(bookInfo,b1);
        listBookNode*b2 = (listBookNode*)listBookNode_new();
        b2->vSet(b2,"java language","123456","zhoujie","1989190");
        bookInfo->vAdd(bookInfo,b2);
        listBookNode*b3 = (listBookNode*)listBookNode_new();
        b3->vSet(b3,"python language","98765","zhoujie","198990");
        bookInfo->vAdd(bookInfo,b3);
    	
    	// 判断节点是否为空
        printf("isempty:%d\n",bookInfo->vIsEmty(bookInfo));
        // 查找书籍信息
        listBookNode*res = bookInfo->vGetInfoByBookName(bookInfo,"java language");
        if(res)
            printf("result1 of finding: %s\n",res->_bookName);
        else 
            printf("result1:not finding\n");
        // 显示书籍信息
        bookInfo->vDispaly(bookInfo);
        // 删除对应名字的书籍
        bookInfo->vDeleteBookInfoByName(bookInfo,"java language");
        // 再次查找删除对应名字的书籍   
        res = bookInfo->vGetInfoByBookName(bookInfo,"java language");
        if(res)
            printf("result2 of finding: %s\n",res->_bookName);
        else 
            printf("result2: not finding\n");
        // 显示链表中存储的书籍
        bookInfo->vDispaly(bookInfo);
    	return 0;
    }

    book.h

    c 复制代码
    #ifndef _BOOK_H
    #define _BOOK_H
    
    #include "lw_oopc.h"
    
    // 链表相关
    CLASS (listBookNode)
    {
        char _bookName[15];
        char _bookNumber[20];
        char _authorName[15];
        char _authorTel[15];
        listBookNode*next;
        void (*vInit) (void*);
        void (*vSet) (void*,char*,char*,char*,char*);
    };
    
    CLASS (bookList)
    {
        void (*vInit) (void*);
        void (*vAdd) (void*,listBookNode*);
        int (*vIsEmty) (void*);
        listBookNode* (*vGetInfoByBookName) (void*,char*);
        void (*vDispaly) (void*);
        void (*vDeleteBookInfoByName) (void*,char*);
        int listCount;
        listBookNode* next;
    };
    #endif //_BOOK_H

    book.c

    c 复制代码
    #include "stdio.h"
    #include "book.h"
    #include "lw_oopc.h"
    
    int main(void)
    {
        bookList*bookInfo = (bookList*)bookList_new();
        listBookNode*b1 = (listBookNode*)listBookNode_new();
        b1->vSet(b1,"C language","123123","zhoujie","19891890");
        bookInfo->vAdd(bookInfo,b1);
        listBookNode*b2 = (listBookNode*)listBookNode_new();
        b2->vSet(b2,"java language","123456","zhoujie","1989190");
        bookInfo->vAdd(bookInfo,b2);
        listBookNode*b3 = (listBookNode*)listBookNode_new();
        b3->vSet(b3,"python language","98765","zhoujie","198990");
        bookInfo->vAdd(bookInfo,b3);
    
    
        printf("%d  name:%s\n",bookInfo->listCount,bookInfo->next->_bookName);
        printf("isempty:%d\n",bookInfo->vIsEmty(bookInfo));
        listBookNode*res = bookInfo->vGetInfoByBookName(bookInfo,"java language");
        if(res)
            printf("result1 of finding: %s\n",res->_bookName);
        else 
            printf("result1:not finding\n");
        bookInfo->vDispaly(bookInfo);
        bookInfo->vDeleteBookInfoByName(bookInfo,"java language");
        res = bookInfo->vGetInfoByBookName(bookInfo,"java language");
        if(res)
            printf("result2 of finding: %s\n",res->_bookName);
        else 
            printf("result2: not finding\n");
        bookInfo->vDispaly(bookInfo);
    	return 0;
    }

    结果 Makefile源文件

    c 复制代码
    # 声明伪目标
    .PHONY:clean
    
    # 指定make最终生成的文件
    TARGET := target
    # 指定依赖文件
    OBJ =  book.o 
    
    $(TARGET) : $(OBJ)
    	gcc -o $@ main.c  $^ 
    
    # 编译某一个文件  $@表示目标  $^表示依赖
    %.o : %.c
    	gcc -c -o $@ $^

    上述两种实现方式均可使用这个makefile文件。   使用makefile文件的好处是:在某个项目中,如果只有一个文件受到改动,那么编译时就可不必花多余时间编译没有改动过的文件,直接编译已经改动过的文件与主文件即可。(这个现象在一个大工程中更能直观体现,但是在小项目中可以查看编译过程的命令) &esmp;&esmp;实现上述的优点主要是使用了依赖,也就是说如果某个目标文件的依赖没有发生更新,那么他自己也是不需要更新的。代码体现在:

    c 复制代码
    # 编译某一个文件  $@表示目标  $^表示依赖
    %.o : %.c
    	gcc -c -o $@ $^

    符号"%"是一个通配符,也就是能够表达符合这个条件的所有文件,比如:%.o可以表示a.o、b.o、c.o、d.o......

    遇到的问题

    报错1

    报错描述

    小编直接使用vscode+gcc无法运行,会出现报错 undefined reference to `bookList_new'。这个报错小编最终锁定在bookListbookInfo = (bookList)bookList_new();

    ** 分析及解决方案**

    小编分析,这玩意与编译链接有关(这方面小编不太熟悉)。小编最终是使用 vscode+Makefile+gcc,完成编译操作的,当然了运行也是在终端中完成的。

    报错二

    问题描述

    当我们在使用类初始化bookListbookInfo = (bookList)bookList_new();时,调用的xxx_new()函数少括号时,编译器是不会发现的,但是实际运行时程序就会卡死。

    分析与解决方案

    这里的解决方案比较简单,只需要在xxx_new()函数后加上一个括号即可。

相关推荐
咕噜Yuki06092 天前
Java基础篇:学会这些技能,程序员职场竞争力UP UP
java·开发语言·编程语言
codeGoogle3 天前
计算机书籍打包
前端·后端·编程语言
Moonbit4 天前
MoonBit 双周报 Vol.59:新增编译器常量支持,改进未使用警告,支持跨包函数导入...多个关键技术持续优化中!
编程语言
神经星星4 天前
【TVM 教程】外部张量函数
人工智能·开源·编程语言
Moonbit7 天前
MGPIC案例分享|零基础早鸟教程:8小时使用 wasm4 开发井子棋小游戏!
编程语言
邓校长的编程课堂10 天前
少儿编程进入义务教育课程:培养信息科技素养的新政策解读
科技·编程语言·少儿编程·信息学竞赛·科技特长生·义务教育
Moonbit18 天前
MoonBit 双周报 Vol.58:原生后端支持、多行字符串插值、json.inspect 功能等多项关键特性取得显著进展!
编程语言
小尤笔记1 个月前
Python操作系统的6个自动化脚本
数据库·python·自动化·php·编程语言·python入门
神经星星1 个月前
【TVM 教程】使用 Relay Visualizer 可视化 Relay
人工智能·机器学习·编程语言
GoppViper2 个月前
golang学习笔记17——golang使用go-kit框架搭建微服务详解
笔记·后端·学习·微服务·golang·编程语言·go-kit