电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
适合具备 C 语言基础的 C++ 教程(九)
分 享
扫描二维码分享
适合具备 C 语言基础的 C++ 教程(九)
C++
wenzi 嵌入式软件
关注
发布时间: 2021-03-15
丨
阅读: 925
# 前言 在上一则教程中,叙述了关于`C++`类型转换的相关内容,在本节教程中,将叙述 `C++`的另一个内容,也就是**抽象**,这也是 `C++`相对于 `C`语言来说独特的一点,下面我们就来着重叙述这一点。 ## 纯虚函数 在介绍**抽象类**之前,需要弄明白何为纯虚函数,下面假定我们有这样一个需求: > 做一个“各个国家的人的调查”,调查各个国家的人的:饮食、穿衣、开车 要完成这样一个事情,那我们现在就需要实现这样几个类,一个是 `Human`类,其他国家的人从 `Human`类里派生而来,就比如说是`Chinese`和`Englishman`,我们再回过头来想,我们所要实现的需求是调查`各个国家的人`,那么这个过程中,由`Human`类派生得到 `Chinese`和 `Englishman`,那么在实例化对象的时候,我们实际上是不会用到`Human`类去定义一个对象的,考虑到这层因素,我们在 `Human`类里使用到了纯虚函数的概念,类实现的代码如下所示: ```cpp 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"<
#include
#include
using namespace std; class Chinese { public: void eating(void); void wearing(void); void drivering(void); }; #endif ``` 通过上述地`.h`文件可以看出,在这里的`Chinese`类中,它只涉及到类成员函数的一个声明,并没有成员函数的实现,我们继续来看`Chinese.cpp`的类实现: ```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`中的代码,代码如下所示: ```cpp #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`中的代码,代码如下所示: ```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; } ``` 至此,除了主函数以外的代码就编写完了,我们继续来看主函数的代码: ```cpp #include "Englishman.h" #include "Chinese.h" int main(int argc, char **argv) { Englishman e; Chinese c; e.eating(); c.eating(); return 0; } ``` 在前面的教程中,我们就说过,如果是多文件的话,需要编写 `Makefile`文件,`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](https://gitee.com/wenzi_D/images4mk/raw/master/3.png) 上述代码中,如果我们想要增添功能,比如说`Chinese`和`Englishman`都有名字,那么就可以增添设置名字和获取名字这两种方法,首先是 `Chinese`的代码,代码如下: ```cpp #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`中的代码: ```cpp #include "Chinese.h" void Chinese::setName(char *name) { this->name = name; } char *Chinese::getName(void) { return this->name; } /@@*其他成员函数实现同上,这里省略*/ ``` 写完了 `Chinese`的代码,然后是`Englishman`中的代码,首先是`Englishman.h`中的代码: ```cpp #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`中的代码: ```cpp #include "Englishman.h" void Englishman::setName(char *name) { this->name = name; } char *Englishman::getName(void) { return this->name; } ``` 以这样的方式增添功能,确实是可行的,但是我们假设一下,如果类很多,除了中国人和英国人还有很多个国家的人,如果这些类都要增加相同的功能,这个工作量就比较大了,那要如何解决这个问题呢?这个时候,我们就可以引入一个新类`Human`,然后,将每个类相同的部分写在这个类里面,其他类,诸如`Englisnman`和`Chinese`就可以从`Human`类中继承而来,那这个时候,增添的操作,就只需要在 `Human`类中增加就好了,不需要改动`Chinese`和`Englishman`,工作量就小了很多。我们来看 `Human`类的代码实现,首先是`.h`代码的实现: ```cpp #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`代码的实现: ```cpp #include "Human.h" void Human::setName(char *name) { this->name = name; } char *Human::getName(void) { return this->name; } ``` 有了 `Human`类之后,我们就可以来实现我们所说的 `Englishman`和`Chinese`类了,代码如下所示: ```cpp #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`的代码: ```cpp #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 ``` 可以看到 `Englishman`和`Chinese`都是继承自`Human`类,这个时候,就不需要再自己实现`setName`和`getName`了。 我们继续来完善我们的代码,先从主函数说起,主函数代码如下所示: ```cpp void test_eating(Human *h) { h->eating(); } int main(int argc, char **argv) { Englishman e; Chinese c; Human * h[2] = {&e,&h}; int i; for (i = 0; i < 2; i++) test_eating(h[i]); return 0; } ``` 简要说明一下主函数代码的意思,其实就是定义了一个指针数组,然后遍历整个指针数组,一次将数组内的成员传入`test_eating()`函数内,根据传入的参数不同执行不同的`eating`函数,说到这里,实际上是跟前面一则教程中所将的抽象类和虚函数概念所结合起来的,因此,这里也是采用相同的思路,将 `Human`类设置为抽象类,然后其他类由`Human`类派生而来,下面就来看`Human`类的代码: ```cpp #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); virtual void eating(void) = 0; virtual void wearing(void) = 0; virtual void driving(void) = 0; }; #endif ``` 然后是`Human.cpp`的代码: ```cpp #include "Human.h" void Human::setName(char *name) { this->name = name; } char *Human::getName(void) { return this->name; } ``` 实现了 `Human`类的代码之后,我们来看`Chinese`和`Englishman`的代码,代码如下所示,首先是 `Englishman.h`: ```cpp #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); }; #endif ``` 紧接着是 `Englishman.cpp`的代码: ```cpp #include "Englishman.h" void Englishman::eating(void) { cout<<"use knife to eat"<
eating(); } int main(int argc, char **argv) { Englishman e; Chinese c; Human* h[2] = {&e, &c}; int i; for (i = 0; i < 2; i++) test_eating(h[i]); return 0; } ``` 然后,我们进行编译,运行: ![image-20210223190725028](https://gitee.com/wenzi_D/images4mk/raw/master/4.png) 在上述中,我们看到编译我们是用`make`命令进行编译的,然后在运行可执行代码的时候,我们采用的是`LD_LIBRARY_PATH=./ ./Human`,与前面的教程不同,这次在运行可执行文件的时候,多了`LD_LIBRARY_PATH=./`,这是因为现在使用了动态库,而这条多出来的语句是来指明动态库的路径的。 最后,我们来测试一下,我们使用动态链接库所带来的优点,比如,我现在更改了` Chinese.cpp`的`eating`函数,代码如下: ```cpp void Chinese::eating(void) { cout<<"use chopsticks to eat,test"<
链接:https://pan.baidu.com/s/1fB78jG6PdMNcXMfPwtqyvw > 提取码:cquv
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
wenzi 嵌入式软件
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交