7. 多态
7.1 多态基本用法
1 #include<iostream>
2 using namespace std;
3
4 // 多态
5
6 // 动态多态满足条件:
7 // 1.有继承关系
8 // 2. 子类重写父类的虚函数
9 //
10 // 动态多态使用
11 // 父类的指针或者引用,指向子类对象
12 //
13
14 // 动物类
15 class Animal {
16 public:
17 // 虚函数,函数地址晚绑定
18 virtual void speak() {
19 cout << "动物会说话" << endl;
20 }
21 };
22
23 // 猫类
24 class Cat:public Animal {
25 public:
26 // 父类 虚函数 重写
27 // 重写:函数返回值类型、函数名、参数列表 完全相同
28 void speak() {
29 cout << "小猫在说话" << endl;
30
31 }
32 };
33
34 // 狗类
35 class Dog :public Animal {
36 public:
37 void speak() {
38 cout << "小狗在说话" << endl;
39
40 }
41 };
42
43 // 执行说话函数
44 // 地址早绑定,在编译阶段确定函数地址
45 // 如果想执行“猫说话”,那么这个函数地址就不能早绑定,需要在运行阶段进行绑定,即地址晚绑定
46 void doSpeak(Animal& animal) { // 父类引用接收子类对象
47 // 通过对基类定义虚函数的方法
48 // 调用speak()函数时,函数地址根据传入的对象而动态绑定函数地址
49 animal.speak();
50 }
51
52 void test01() {
53 Cat cat;
54 doSpeak(cat); // 父类引用接收子类对象
55
56 Dog dog;
57 doSpeak(dog);
58 }
59
60 int main() {
61
62 test01();
63
64 system("pause");
65
66 return 0;
67 }
68
69 // 总结
70 // 多态
71 // 分类:
72 // 静态多态:函数重载、运算符重载
73 // 动态多态:派生类、虚函数
74 // 静态多态与动态多态的区别:
75 // 静态:函数地址早绑定,编译阶段确定函数地址
76 // 动态:函数地址晚绑定,运行阶段确定函数地址
77 // 多态优点:
78 // 代码组织结构清晰
79 // 可读性强
80 // 有利于前期和后期的扩展以及维护
81 //
7.2 多态案例(一) 计算器
1 #include<iostream>
2 #include<string>
3
4 using namespace std;
5
6 // 普通实现
7 class Calculator {
8 public:
9 int getResult(string oper) {
10 if (oper == "+") {
11 return m_Num1 + m_Num2;
12 }
13 else if (oper == "-")
14 {
15 return m_Num1 - m_Num2;
16 }
17 else if (oper == "*") {
18 return m_Num1 * m_Num2;
19 }
20 }
21
22 int m_Num1; // 操作数1
23 int m_Num2; // 操作数2
24 };
25
26 // 利用多态实现计算器
27
28 // 实现计算器抽象类
29 class AbstractCalculater {
30 public:
31
32 virtual int getResult() {
33 return 0;
34
35 }
36 int m_Num1;
37 int m_Num2;
38 };
39
40 // 加法计算器类
41 class AddCalculator : public AbstractCalculater {
42 int getResult() {
43 return m_Num1 + m_Num2;
44 }
45 };
46
47 // 减法计算器类
48 class SubCalculator : public AbstractCalculater {
49 int getResult() {
50 return m_Num1 - m_Num2;
51 }
52 };
53
54 // 乘法计算器类
55 class MulCalculator : public AbstractCalculater {
56 int getResult() {
57 return m_Num1 * m_Num2;
58 }
59 };
60
61
62 void test01() {
63
64 // 普通实现
65 Calculator c;
66 c.m_Num1 = 20;
67 c.m_Num2 = 10;
68
69 cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;
70 cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;
71 cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
72 }
73
74 void test02() {
75 // 多态使用条件
76 // 父类指针或者引用指向子类对象
77
78 // 加法运算
79 AbstractCalculater* abc = new AddCalculator;
80 abc->m_Num1 = 20;
81 abc->m_Num2 = 10;
82 cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;
83 // 堆区数据,用完后记得销毁
84 delete abc;
85
86 // 减法运算
87 abc = new SubCalculator;
88 // 上面的delete abc只是释放了堆区数据,abc依旧是个父类的指针
89 abc->m_Num1 = 20;
90 abc->m_Num2 = 10;
91 cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;
92 delete abc;
93
94 // 相乘运算
95 abc = new MulCalculator;
96 abc->m_Num1 = 20;
97 abc->m_Num2 = 10;
98 cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;
99 delete abc;
100
101 }
102
103 int main() {
104
105 //test01();
106
107 test02();
108
109 system("pause");
110
111 return 0;
112
113 }
114
115 // 总结
116 // 在真正的开发中,提倡 开闭原则
117 // 开闭原则: 对扩展进行开放,对修改进行关闭
118 //
7.3 纯虚函数和抽象类
1 #include<iostream>
2 using namespace std;
3
4 // 纯虚函数与抽象类
5
6 class Base {
7 public:
8 // 纯虚函数
9 // 该类为抽象类
10 virtual void func() = 0;
11 };
12
13 class Son :public Base {
14 public:
15 void func() {
16 cout << "子类重写了父类的纯虚函数!" << endl;
17 }
18 };
19
20 void test01() {
21 //Base b; // 报错,抽象类,无法实例化对象
22 //new Base; // 报错,堆区也无法实例化
23
24 //Son s; // 报错,子类需要重写抽象类(父类)的纯虚函数
25
26 Son s;
27 s.func();
28 }
29
30 int main() {
31
32 test01();
33
34 system("pause");
35
36 return 0;
37 }
38
39
40 // 总结
41 // 在多态中,通常父类中的虚函数的实现是毫无意义的,主要都是调用子类重写的内容
42 // 因此可以将虚函数改为传虚函数
43 //
44 // 纯虚函数语法: virtual 返回值类型 函数名 (参数列表) = 0;
45 //
46 // 当类中有了纯虚函数,这类也成为抽象类
47 //
48 // 抽象类特点:
49 // 无法实例化对象
50 // 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
51 //
52 //
7.4 多态案例(二) 制作饮品
1 #include<iostream>
2 #include<string>
3
4 using namespace std;
5
6 // 多态案例2 制作饮品
7 class AbstractDrinking {
8 public:
9 // 煮水
10 virtual void Boil() = 0;
11
12 // 冲泡
13 virtual void Brew() = 0;
14
15 // 倒入水中
16 virtual void PourInCup() = 0;
17
18 // 加入辅料
19 virtual void PutSomething() = 0;
20
21 // 制作饮品
22 void makeDrink() {
23 Boil();
24 Brew();
25 PourInCup();
26 PutSomething();
27 }
28
29 };
30
31 // 制作咖啡
32 class Coffee : public AbstractDrinking {
33 public:
34 // 煮水
35 virtual void Boil() {
36 cout << "煮农夫山泉" << endl;
37 }
38
39 // 冲泡
40 virtual void Brew() {
41 cout << "冲泡咖啡" << endl;
42 }
43
44 // 倒入杯中
45 virtual void PourInCup() {
46 cout << "倒入杯中" << endl;
47 }
48
49 // 加入辅料
50 virtual void PutSomething() {
51 cout << "加入糖和牛奶" << endl;
52 }
53 };
54
55 // 制作奶茶
56 class MilkTea : public AbstractDrinking {
57 public:
58 // 煮水
59 virtual void Boil() {
60 cout << "煮农百岁山" << endl;
61 }
62
63 // 冲泡
64 virtual void Brew() {
65 cout << "冲泡珍珠" << endl;
66 }
67
68 // 倒入杯中
69 virtual void PourInCup() {
70 cout << "倒入杯中" << endl;
71 }
72
73 // 加入辅料
74 virtual void PutSomething() {
75 cout << "加入珍珠、果粒、椰蓉" << endl;
76 }
77 };
78
79 void doWork(AbstractDrinking* abs) {
80 abs->makeDrink();
81 delete abs;
82 }
83
84 void test01() {
85 // 制作咖啡
86 cout << "制作咖啡" << endl;
87 doWork(new Coffee);
88
89 cout << "\n制作奶茶" << endl;
90 doWork(new MilkTea);
91 }
92
93 int main() {
94
95 test01();
96
97 system("pause");
98
99 return 0;
100 }
7.5 虚析构与纯虚析构
1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5
6 class Animal {
7 public:
8 virtual void speak() = 0;
9 Animal() {
10 cout << "Animal的构造函数" << endl;
11 }
12 // 虚析构
13 //virtual ~Animal() {
14 // cout << "Animal的析构函数" << endl;
15 //}
16
17 // 纯虚析构 需要声明,也需要函数实现
18 virtual ~Animal() = 0;
19 // 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
20
21 };
22
23 Animal::~Animal() {
24 cout << "Animal的纯析构函数" << endl;
25 }
26
27 class Cat :public Animal {
28 public:
29 Cat(string name) {
30 cout << "Cat的构造函数" << endl;
31 m_Name = new string(name);
32 }
33 void speak() {
34 cout << *m_Name << "小猫在说话" << endl;
35 }
36
37 string* m_Name;
38
39 ~Cat() {
40 cout << "Cat的析构函数" << endl;
41 if (m_Name != NULL) {
42 delete m_Name;
43 m_Name = NULL;
44 }
45 }
46 };
47
48 void test01() {
49 Animal* animal = new Cat("Tom");
50 animal->speak();
51 delete animal;
52 // 父类指针在析构的时候,不会调用子类中的析构函数,
53 // 导致子类如果存在堆区数据,会出现内存泄露情况
54 // 解决方法:父类改为虚析构
55 // 这样就会释放子类的内存(走子类的析构函数)
56
57
58
59 }
60
61 int main() {
62
63 test01();
64
65 system("pause");
66
67 return 0;
68 }
69
70 // 总结
71 // 虚析构与纯虚析构
72 // 多态使用时,如果子类中有属性开辟到堆区,那么父类指针析构函数无法调用到子类的析构代码
73 // 解决方案:将父类的析构函数改为虚析构或者纯虚析构
74 //
75 // 虚析构与纯虚析构共性:
76 // 可以解决父类指针释放子类对象
77 // 都需要具体的函数实现
78 //
79 // 虚析构与纯虚析构区别:
80 // 如果是纯虚析构,该类属于抽象类,无法实例化对象
81 //
82 // 虚析构:virtual ~类名(){}
83 //
84 // 纯虚析构:
85 // virtual ~类名() = 0;
86 // // 在类外需要初始化
87 // 类名::~类名(){}
88 //
89 // 其他结论
90 // 1.虚析构和纯虚析构就是用来解决父类指针释放子类对象的
91 // 2.如果子类中没有堆区数据,也可以不写虚析构或纯虚析构
92 // 3.拥有纯虚析构的类也属于抽象类,无法实例化对象
93 //
参考:《黑马程序员》C++教程
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear
我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint
(本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展 是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。 如:有三个人,每个人做的不同的事物,但是是需要协作的完成。 而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据
有这个:classEventtrueenduser=User.create!我可以:Event.create!(:historizable=>user)但我不能:Event.where(:historizable=>user)#Mysql2::Error:Unknowncolumn'events.historizable'in'whereclause'我必须改为这样做:Event.where(:historizable_id=>user.id,:historizable_type=>user.class.name)更新重现问题的代码:https://gist.github.com/fg
我有一个UserType和一个可以是Writer或Account的userable。对于GraphQL,我想也许我可以像这样使用UserableUnion:UserableUnion=GraphQL::UnionType.definedoname"Userable"description"AccountorWriterobject"possible_types[WriterType,AccountType]end然后像这样定义我的用户类型:UserType=GraphQL::ObjectType.definedoname"User"description"Auserobject"fie
文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就
目录1关系运算符2运算符优先级3关系表达式的书写代码实例:下面是面试中可能遇到的问题:1关系运算符C++中有6个关系运算符,用于比较两个值的大小关系,它们分别是:运算符描述==等于!=不等于小于>大于小于等于>=大于等于这些运算符返回一个布尔值,即true或false。例如,当x等于y时,x==y的结果为true,否则结果为false。2运算符优先级在C++中,关系运算符的优先级高于赋值运算符,但低于算术运算符。以下是关系运算符的优先级,从高到低排列:运算符描述>,,>=,关系运算符==,!=相等性运算符&&逻辑与`如果在表达式中有多个运算符,则按照优先级顺序依次进行运算。3关系表达式的书写在
一.计算机组成原理 这本书利用组合逻辑、同步时序逻辑电路设计的相关知识,从逻辑门开始逐步构建运算器、存储器、数据通路和控制器,最终集成为完整的CU原型系统,使读者从设计者的角度理解计算机部件构成及运行的基本原理,掌握软硬件协同的概念。 全书共9章,主要内容包括计算机系统概述、数据信息的表示、运算方法与运算器、存储系统、指令系统、中央处理器、指令流水线、总线系统、输入输出系统。1.计算机系统概述1.1计算机发展历程 计算机是一种能够按照事先存储的程序,自动、高速、准确地对相关信息进行处理的电子设备。1946年2月,世界上第一台电子数字计算机ENIAC(ElectronicNum