当前位置:首页 > 公众号精选 > wenzi嵌入式软件
[导读]本文将叙述 C 的另一个内容,也就是抽象,这也是 C 相对于 C语言来说独特的一点。

前言

在上一则教程中,叙述了关于C 类型转换的相关内容,在本节教程中,将叙述 C 的另一个内容,也就是抽象,这也是 C 相对于 C语言来说独特的一点,下面我们就来着重叙述这一点。

纯虚函数

在介绍抽象类之前,需要弄明白何为纯虚函数,下面假定我们有这样一个需求:

做一个“各个国家的人的调查”,调查各个国家的人的:饮食、穿衣、开车

要完成这样一个事情,那我们现在就需要实现这样几个类,一个是 Human类,其他国家的人从 Human类里派生而来,就比如说是ChineseEnglishman,我们再回过头来想,我们所要实现的需求是调查各个国家的人,那么这个过程中,由Human类派生得到 Chinese和 Englishman,那么在实例化对象的时候,我们实际上是不会用到Human类去定义一个对象的,考虑到这层因素,我们在 Human类里使用到了纯虚函数的概念,类实现的代码如下所示:

class Human
{

private:
    int a;
public:
    /*纯虚函数*/
    virtual void eating(void) 0;
    virtual void wearing(void) 0;
    virtual void driving(void) 0;
};

class Englishman : public Human
{
public:
    void eating(void)  cout<<"use knife to eat"<<endl; }
    void wearing(void) {cout<<"wear english style"<<endl; }
    void driving(void) {cout<<"drive english car"<<endl; }
};

class Chinese : public Human 
{
public:
    void eating(void)  cout<<"use chopsticks to eat"<<endl; }
    void wearing(void) {cout<<"wear chinese style"<<endl; }
    void driving(void) {cout<<"drive chinese car"<<endl; }
};
我们可以看到在上述的代码中,Human类的成员函数跟前几讲所写的成员函数有所不同,而如上述 Human类的成员函数这般写法,也就被称之为是纯虚函数

抽象类

上述引出了纯虚函数的写法,那纯虚函数和抽象类之间有什么关系呢?实际上,抽象类就是具有纯虚函数的类,那这抽象类存在的意义是什么呢?总的来说,其作用也就是:向下定义好框架,向上提供统一的接口,其不能够实例化对象,基于上述几个类的前提下,我们编写主函数的代码:

int main(int argc,char **argv)
{
    Human h;

    return 0;
}
因为抽象类不能够实例化对象,所以上述代码编译结果是错误的,错误信息如下所示:

而使用通过抽象类派生得到的派生类实例化对象是可行的,代码如下所示:

int main(int argc, char** argv)
{
    Englishman e;
    Chinese    g;

    return 0;
}
另外需要注意的是:在派生抽象类的过程中,如果派生得到的子类没有覆写所有的纯虚函数,那么这个子类还是抽象类,比如有如下所示的代码,Human类沿用的是上述的写法,代码不变,如果我们将上述的 Chinese类进行更改,更改后的代码如下所示:

class Chinese : public Human 
{
public:
    void eating(void) cout<<"use chopsticks to eat"<<endl; }
    void wearing(void) {cout<<"wear chinese style"<<endl; }
    //void driving(void) {cout<<"drive chinese car"<
};
如上述代码所示,我们将 driving()函数注释掉了,那么也就是说,我们并没有将抽象类的全部纯虚函数进行覆写,那么当前这个Chinese类也是一个抽象类,也是不能够进行实例化对象的,要使得 Chinese类有作用,我们必须派生出来另一个类,代码如下所示:

class Guangximan : public Chinese 
{
    void driving(void) {cout<<"drive guangxi car"<<endl; }
};
这个时候,就可以用 Guangximan这个类来实例化对象了。

多文件编程

在前面的教程中,有一则教程说到了多文件编程,在 C 中也就是将类的声明放到头文件中,将类的实现放在.cpp文件中,为了更好地阐述这种方法,我们用实例来进行讲解,首先,来看一下,所涉及到地所有文件有哪些:

image-20210222103409774
可以看到上述有6个文件,我们首先来看 Chinese.h这个文件,代码如下所示:

#ifndef _CHINESE_H
#define _CHINESE_H

#include 
#include 
#include 

using namespace std;

class Chinese
{

public:
    void eating(void)
    void wearing(void);
    void drivering(void);
};

#endif
通过上述地.h文件可以看出,在这里的Chinese类中,它只涉及到类成员函数的一个声明,并没有成员函数的实现,我们继续来看Chinese.cpp的类实现:

#include "Chinese.h"

void Chinese::eating(void)
{
    cout << "use chopsticks to eat" << endl;
}

void Chinese::wearing(void)
{
    cout << "wear chinese style" << endl;
}

void Chinese::drivering(void)
{
    cout << "driver china car" << endl;
}
按照上述这样一种方法,我们继续来实现Englishman类中的代码,首先是Englishman.h中的代码,代码如下所示:

#ifndef _ENGLISHMAN_H
#define _ENGLISHMAN_H

#include 
#include 
#include 

using namespace std;

class Englishman
{

public:
    void eating(void);
    void wearing(void);
    void driver(void);
};

#endif
继续看.cpp中的代码,代码如下所示:

#include "Englishman.h"

void Englishman::eating(void)
{
    cout << "use chopsticks to eat" << endl;
}

void Englishman::wearing(void)
{
    cout << "wear chinese style" << endl;
}

void Englishman::drivering(void)
{
    cout << "driver china car" << endl;
}
至此,除了主函数以外的代码就编写完了,我们继续来看主函数的代码:

#include "Englishman.h"
#include "Chinese.h"

int main(int argc, char **argv)
{
    Englishman e;
    Chinese c;

    e.eating();
    c.eating();

    return 0;
}
在前面的教程中,我们就说过,如果是多文件的话,需要编写 Makefile文件,Makefile文件代码如下:

Human: main.o Chinese.o Englishman.o Human.o
    g  -o $@ $^

%.o : %.cpp
    g  -c -o $@ $<

clean:
    rm -f *.o Human 
上述代码就不再这里赘述了,跟之前教程中的 Makefile基本是一样的,有了Makefile之后,编译代码只需要使用 make命令就行了,编译结果如下所示:

image-20210222105051169
上述代码中,如果我们想要增添功能,比如说ChineseEnglishman都有名字,那么就可以增添设置名字和获取名字这两种方法,首先是 Chinese的代码,代码如下:

#ifndef _CHINESE_H
#define _CHINESE_H

#include 
#include 
#include 

using namespace std;

class Chinese{
private:
    char *name;
public:
    void setName(char *name);
    char *getName(void);
    void eating(void);
    void wearing(void);
    void driving(void);
    ~Chinese();
};

#endif
然后是.cpp中的代码:

#include "Chinese.h"

void Chinese::setName(char *name) 
{
    this->name = name;
}

char *Chinese::getName(void
{
    return this->name;
}

/*其他成员函数实现同上,这里省略*/
写完了 Chinese的代码,然后是Englishman中的代码,首先是Englishman.h中的代码:

#ifndef _ENGLISHMAN_H
#define _ENGLISHMAN_H

#include 
#include 
#include 

using namespace std;

class Englishman {
private:
    char *name;
public:
    void setName(char *name);
    char *getName(void);
    void eating(void);
    void wearing(void);
    void driving(void);
    ~Englishman();
};

#endif
紧接着,是.cpp中的代码:

#include "Englishman.h"

void Englishman::setName(char *name) 
{
    this->name = name;
}

char *Englishman::getName(void
{
    return this->name;
}
以这样的方式增添功能,确实是可行的,但是我们假设一下,如果类很多,除了中国人和英国人还有很多个国家的人,如果这些类都要增加相同的功能,这个工作量就比较大了,那要如何解决这个问题呢?这个时候,我们就可以引入一个新类Human,然后,将每个类相同的部分写在这个类里面,其他类,诸如EnglisnmanChinese就可以从Human类中继承而来,那这个时候,增添的操作,就只需要在 Human类中增加就好了,不需要改动ChineseEnglishman,工作量就小了很多。我们来看 Human类的代码实现,首先是.h代码的实现:

#ifndef _HUMAN_H
#define _HUMAN_H

#include 
#include 
#include 

using namespace std;

class Human {
private:
    char *name;

public:
    void setName(char *name);
    char *getName(void);    
};

#endif
然后是.cpp代码的实现:

#include "Human.h"

void Human::setName(char *name) 
{
    this->name = name;
}

char *Human::getName(void
{
    return this->name;
}
有了 Human类之后,我们就可以来实现我们所说的 EnglishmanChinese类了,代码如下所示:

#ifndef _ENGLISHMAN_H
#define _ENGLISHMAN_H

#include 
#include 
#include 

#include "Human.h"

using namespace std;

class Englishman : public Human 
{
public:
    void eating(void);
    void wearing(void);
    void driving(void);
    ~Englishman();
};

#endif
然后是Chinese的代码:

#ifndef _CHINESE_H
#define _CHINESE_H

#include 
#include 
#include 

#include "Human.h"

using namespace std;

class Chinese : public Human
{
public:
    void eating(void);
    void wearing(void);
    void driving(void);
    ~Chinese();
};

#endif
可以看到 EnglishmanChinese都是继承自Human类,这个时候,就不需要再自己实现setNamegetName了。

我们继续来完善我们的代码,先从主函数说起,主函数代码如下所示:

void test_eating(Human *h)
{
    h->eating();
}

int main(int argc, char **argv)
{
    Englishman e;
    Chinese c;

    Human * h[2] = {
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭