【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()函数后加上一个括号即可。

相关推荐
神经星星1 小时前
【TVM教程】在 Arduino 上为 microTVM 训练视觉模型
人工智能·机器学习·编程语言
明月与玄武1 天前
Python编程的真谛:超越语法,理解编程本质
python·编程语言
Mirageef3 天前
aardio界面和控件
编程语言
Mirageef5 天前
aardio批处理脚本
编程语言
楽码5 天前
理解go指针和值传递
后端·go·编程语言
帽儿山的枪手9 天前
什么是字节流?
c语言·go·编程语言
楽码9 天前
一文看懂隐藏功能!语言的逃逸分析
后端·go·编程语言
神经星星9 天前
【TVM教程】microTVM TFLite 指南
人工智能·机器学习·编程语言
马可奥勒留9 天前
mojo🔥学习笔记——变量
编程语言
Mirageef10 天前
aardio-给控制台化妆
编程语言