-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathastringent.sql
199 lines (188 loc) · 237 KB
/
astringent.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
-- --------------------------------------------------------
-- 主机: 127.0.0.1
-- 服务器版本: 10.3.15-MariaDB - mariadb.org binary distribution
-- 服务器操作系统: Win64
-- HeidiSQL 版本: 9.5.0.5196
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- 正在导出表 astringent.a_attention 的数据:~3 rows (大约)
/*!40000 ALTER TABLE `a_attention` DISABLE KEYS */;
INSERT INTO `a_attention` (`USER_ID`, `USER_FOLLOWED`, `FOLLOWED_TIME`) VALUES
(1000000, 1000000, '2020-06-08 15:37:37'),
(1000000, 1000002, '2020-06-09 12:46:20'),
(1000002, 1000000, '2020-06-09 14:22:19');
/*!40000 ALTER TABLE `a_attention` ENABLE KEYS */;
-- 正在导出表 astringent.a_carousel 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `a_carousel` DISABLE KEYS */;
INSERT INTO `a_carousel` (`NUMBER`, `IMG_URL`, `IMG_TITLE`, `LINK`) VALUES
(1, '102d720db15b46d698419827eda57209.jpg', 'C++内存如何优化?想了解吗?点这里!', 'video.html?name=c9ef528271954b5ea262113524b53253'),
(2, '246ea5028737458390c0f43bc24b019b.jpg', '想学习C++最新标准吗?', 'video.html?name=138a252e262343e091666d2275aade5e'),
(3, '116d0bb14e85444abd2e3f5d9a6919a6.jpg', 'Mditor编辑器使用方法', 'article.html?name=48aadcaa5ed84ab7880be87ec5b4dd77');
/*!40000 ALTER TABLE `a_carousel` ENABLE KEYS */;
-- 正在导出表 astringent.a_comment 的数据:~14 rows (大约)
/*!40000 ALTER TABLE `a_comment` DISABLE KEYS */;
INSERT INTO `a_comment` (`COMM_ID`, `USER_ID`, `RESOURCES_ID`, `COMMENT_CONTENT`, `COMMENT_DATE`) VALUES
(1, 1000000, 'c6ddbe9340d6436f816a66fc8d0a54ad', '1.双击图标,打开VC6.0如图所示\n2.打开File菜单,新建一个项目,在左侧文件去选择Win32 Console Application,右侧工程名称输入名称如图:1,位置选项选择存放的位置,点击确定\n3.选择要创建的类型,本文创建一个空白工程\n4.显示将要创建的工程信息\n5.确定无误后,进入工程目录\n6.新建一个c++源码文件(左侧文件区选择C++ Source File),右侧同上输入文件名和存放位置\n7.点击确定,新建一个后缀为.cpp的空白文档\n8.新建一个hello world 小实例', '2020-06-03 08:47:04'),
(2, 1000000, '4665714aff6d441397c2f852f2eadef5', '老师讲的非常易懂!', '2020-06-06 18:02:01'),
(3, 1000002, '48aadcaa5ed84ab7880be87ec5b4dd77', '谢谢! 非常好用。', '2020-06-08 13:32:57'),
(4, 1000000, '4665714aff6d441397c2f852f2eadef5', 'eeee', '2020-06-08 15:37:27'),
(5, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '赞', '2020-06-09 12:46:00'),
(6, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '老师讲的非常好!', '2020-06-09 12:46:13'),
(7, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', '嗯,确实不错!', '2020-06-09 12:47:09'),
(8, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', '赞', '2020-06-09 12:47:30'),
(9, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', '像学习更多的看我主页!', '2020-06-09 12:48:13'),
(10, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', '求关注!', '2020-06-09 12:48:44'),
(11, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '请多多支持!', '2020-06-09 12:49:41'),
(12, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '这个#include<iostream> 是干什么的?', '2020-06-09 12:50:25'),
(13, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '没怎么太懂', '2020-06-09 12:50:33'),
(14, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '可以详细说说吗!', '2020-06-09 12:50:41'),
(15, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', 'iostream是指iostream库。iostream的意思是输入输出流,直接点说就是in(输入) out(输出) stream(流),取in、out的首字母与stream合成。', '2020-06-09 12:51:53'),
(16, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '好的,明白了!', '2020-06-09 12:52:58');
/*!40000 ALTER TABLE `a_comment` ENABLE KEYS */;
-- 正在导出表 astringent.a_flie 的数据:~36 rows (大约)
/*!40000 ALTER TABLE `a_flie` DISABLE KEYS */;
INSERT INTO `a_flie` (`FILE_ID`, `RES_ID`, `FILE_NAME`, `FILE_INDEX`, `FILE_TYPE`) VALUES
(1, 'c6ddbe9340d6436f816a66fc8d0a54ad', '5d339406e5ae4878b7f4d05398baf897.webm', 0, 'video/webm'),
(2, 'c9ef528271954b5ea262113524b53253', '49480372662542a8ae0184af803beeb9.webm', 0, 'video/webm'),
(3, '138a252e262343e091666d2275aade5e', 'debe0433fe8140629f28ed2d38097010.webm', 0, 'video/webm'),
(4, 'e0e7d463139948a4a63ebecaa8112710', 'C++ Primer第四版中文版.pdf', 0, 'application/pdf'),
(6, '4e3cb62d2aa7406e9b2b44da552968cb', 'mysql-installer-web-community-8.0.20.0.msi', 0, ''),
(7, '4665714aff6d441397c2f852f2eadef5', 'b49623f31ab0451997575cb2b7e593e5.webm', 0, 'video/webm'),
(8, '4665714aff6d441397c2f852f2eadef5', 'b3e964f62571494c86c0237576d13859.webm', 1, 'video/webm'),
(9, '4665714aff6d441397c2f852f2eadef5', '49480372662542a8ae0184af803beeb9.webm', 2, 'video/webm'),
(10, '4665714aff6d441397c2f852f2eadef5', '251f95e9961c4280b44c246d917082c9.webm', 3, 'video/webm'),
(11, '4665714aff6d441397c2f852f2eadef5', '7477d5d7dd134cd5ba98dbf5dbd50808.webm', 4, 'video/webm'),
(12, '4665714aff6d441397c2f852f2eadef5', '16804143ae48406d878120b5cf68b0f5.webm', 5, 'video/webm'),
(13, '4665714aff6d441397c2f852f2eadef5', '5d339406e5ae4878b7f4d05398baf897.webm', 6, 'video/webm'),
(14, '74d1f9675f6142f5844a102967ef3275', '16804143ae48406d878120b5cf68b0f5.webm', 0, 'video/webm'),
(15, '03bc94ac5fd5431f8884c836f9cdab8b', '其他资源八.jpg', 0, 'image/jpeg'),
(16, '03bc94ac5fd5431f8884c836f9cdab8b', 'ChromeSetup.exe', 1, 'application/x-msdownload'),
(17, '33fd0cd85efa41a1808ac4687d1e7424', 'C++纯代码音乐.rar', 0, ''),
(18, '840bb8534867472087b66b76edc62105', 'Docker Desktop Installer.exe', 0, 'application/x-msdownload'),
(19, '7c4819b3525e4c94972ffb76ea406c0a', 'C和C++关系.webm', 0, 'video/webm'),
(20, '2bcfdbe8dc414a259b81dd5a95a75f0f', 'C中的冒牌货.webm', 0, 'video/webm'),
(21, '2bcfdbe8dc414a259b81dd5a95a75f0f', 'C中的冒牌货二.webm', 1, 'video/webm'),
(22, '8713632e9614452d845b637973e488fd', '三目运算符.webm', 0, 'video/webm'),
(23, '1a052e12c73c442fb1116d24edd7b5e0', '典型错误案例.webm', 0, 'video/webm'),
(24, 'aa8fb6d525e84b83af68f09e819de4fa', 'struts类型加强.webm', 0, 'video/webm'),
(25, '9f5b8f3eaecb4296910f0f39d65cef5d', '图解HTTP.pdf', 0, 'application/pdf'),
(26, '179b6916fc574c199d3799634a0f8f6b', 'Bool类型关键字.webm', 0, 'video/webm'),
(27, '179b6916fc574c199d3799634a0f8f6b', 'Bool类型关键字二.webm', 1, 'video/webm'),
(29, '3f234fc148444c4ca36d23f19ed5bcbf', 'C++对C的扩展.webm', 0, 'video/webm'),
(30, 'd8858a3530944188ae1a9384f6dd8a45', '程序设计发展历程.webm', 0, 'video/webm'),
(31, '0124961ae4b44758b62f69c2e87c1ad8', 'Helloworld.webm', 0, 'video/webm'),
(32, '1f1e50aaeb4945f4ba8c2f9eb6ab0a89', '结论.webm', 0, 'video/webm'),
(33, 'e8e72807a6a240759dd644709cd4464a', '简单C++程序.webm', 0, 'video/webm'),
(34, 'a8dad06ce448473ea5408bfdfbb73343', 'x360ce_x64.zip', 0, 'application/x-zip-compressed'),
(35, 'f1dbb40d7c5948dbaf97184138c31f18', 'C和指针.pdf', 0, 'application/pdf'),
(36, 'de4521a9b1634763bcb17f366510d8a1', 'C++对C的扩展.webm', 0, 'video/webm'),
(37, 'de4521a9b1634763bcb17f366510d8a1', 'C和C++关系.webm', 1, 'video/webm'),
(38, '69e10cdd2851488bbf8ff4e6f6a602c1', 'vc_redist.x64.exe', 0, 'application/x-msdownload'),
(39, '69e10cdd2851488bbf8ff4e6f6a602c1', 'vc_redist.x86.exe', 1, 'application/x-msdownload'),
(40, 'd6e52a17d0f64a12926c5d885a2aaf82', 'C中的冒牌货.webm', 0, 'video/webm'),
(41, 'd6e52a17d0f64a12926c5d885a2aaf82', 'C中的冒牌货二.webm', 1, 'video/webm');
/*!40000 ALTER TABLE `a_flie` ENABLE KEYS */;
-- 正在导出表 astringent.a_history 的数据:~24 rows (大约)
/*!40000 ALTER TABLE `a_history` DISABLE KEYS */;
INSERT INTO `a_history` (`ID`, `USER_ID`, `RESOURCES_ID`, `HISTORY_TIME`) VALUES
(1, 1000000, 'c6ddbe9340d6436f816a66fc8d0a54ad', '2020-06-04 09:42:06'),
(2, 1000000, 'c9ef528271954b5ea262113524b53253', '2020-06-08 15:36:45'),
(3, 1000000, '138a252e262343e091666d2275aade5e', '2020-06-09 12:07:23'),
(4, 1000000, '48aadcaa5ed84ab7880be87ec5b4dd77', '2020-06-08 15:38:09'),
(5, 1000000, '8c73dfcedf5d4202bb5fb77cbc84adda', '2020-06-04 09:43:06'),
(6, 1000000, '4665714aff6d441397c2f852f2eadef5', '2020-06-08 15:37:10'),
(7, 1000000, '74d1f9675f6142f5844a102967ef3275', '2020-06-06 18:09:24'),
(8, 1000000, '03bc94ac5fd5431f8884c836f9cdab8b', '2020-06-06 18:46:37'),
(9, 1000002, 'c6ddbe9340d6436f816a66fc8d0a54ad', '2020-06-08 13:23:12'),
(10, 1000002, '48aadcaa5ed84ab7880be87ec5b4dd77', '2020-06-08 14:21:33'),
(11, 1000002, '8713632e9614452d845b637973e488fd', '2020-06-08 13:33:35'),
(12, 1000002, '9f5b8f3eaecb4296910f0f39d65cef5d', '2020-06-08 13:40:19'),
(13, 1000002, '3b3aafd13c7b4aff8eea93f127413fb1', '2020-06-08 13:50:54'),
(14, 1000002, '13fbf92dfcf74b5a8ddb28820e1d8bf7', '2020-06-08 13:51:26'),
(15, 1000002, 'e782a32a2e744b68a2d46293036deb1a', '2020-06-08 14:52:04'),
(16, 1000002, '0124961ae4b44758b62f69c2e87c1ad8', '2020-06-09 14:22:38'),
(17, 1000002, 'f988b26886e440a1a437d9fbb8705096', '2020-06-08 14:24:54'),
(18, 1000002, '990b01c7f6574561ab881b2a2fbe92d0', '2020-06-08 14:38:54'),
(19, 1000000, '2bcfdbe8dc414a259b81dd5a95a75f0f', '2020-06-08 15:51:29'),
(20, 1000000, '1a052e12c73c442fb1116d24edd7b5e0', '2020-06-09 08:59:36'),
(21, 1000000, '69e10cdd2851488bbf8ff4e6f6a602c1', '2020-06-09 09:38:06'),
(22, 1000000, '0124961ae4b44758b62f69c2e87c1ad8', '2020-06-09 14:34:24'),
(23, 1000002, 'a8dad06ce448473ea5408bfdfbb73343', '2020-06-09 12:51:22'),
(24, 1000002, '48c85c7987b743b8adeee7a1158fc89f', '2020-06-09 14:21:26'),
(25, 1000002, 'd6e52a17d0f64a12926c5d885a2aaf82', '2020-06-09 14:24:36'),
(26, 1000000, 'aa8fb6d525e84b83af68f09e819de4fa', '2020-06-09 14:28:42');
/*!40000 ALTER TABLE `a_history` ENABLE KEYS */;
-- 正在导出表 astringent.a_miscellaneous 的数据:~9 rows (大约)
/*!40000 ALTER TABLE `a_miscellaneous` DISABLE KEYS */;
INSERT INTO `a_miscellaneous` (`MISC_ID`, `CATEGROY`, `DATA_ID`, `DATA_INFO`) VALUES
(1, 1, 1, '用户'),
(2, 1, 3, '会员'),
(3, 1, 5, '管理员'),
(4, 2, 1, '视频资源'),
(5, 2, 2, '文章资源'),
(6, 2, 3, '其他资源'),
(7, 2, 4, '书籍文档'),
(8, 2, 5, '工具软件'),
(9, 2, 6, '项目源码');
/*!40000 ALTER TABLE `a_miscellaneous` ENABLE KEYS */;
-- 正在导出表 astringent.a_report 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `a_report` DISABLE KEYS */;
INSERT INTO `a_report` (`REPORT_ID`, `RESOURCES_ID`, `REPORT_CONTENT`, `REPORT_TIME`) VALUES
(1, '1a052e12c73c442fb1116d24edd7b5e0', '资源内容与视频内容不符合!', '2020-06-09 09:00:01'),
(2, '2bcfdbe8dc414a259b81dd5a95a75f0f', '不符合', '2020-06-09 14:20:17');
/*!40000 ALTER TABLE `a_report` ENABLE KEYS */;
-- 正在导出表 astringent.a_resources 的数据:~25 rows (大约)
/*!40000 ALTER TABLE `a_resources` DISABLE KEYS */;
INSERT INTO `a_resources` (`RES_ID`, `USER_ID`, `RESOURCES_TITLE`, `RESOURCES_LABEL`, `RESOURCES_CONTENT`, `RESOURCES_MARKDOWN`, `RESOURCES_SRC`, `RESOURCES_COVER_SRC`, `UPLOAD_TIME`, `CHECK_NUMBER`, `RESOURCES_TYPE`) VALUES
('0124961ae4b44758b62f69c2e87c1ad8', 1000002, 'HelloWorld入门教程', '入门 Hello C++ 简单', '<h3 id="-">代码</h3>\n<pre><code class="lang-javascript">#include <iostream>\nusing namespace std;\n\nint main() \n{\n cout << "Hello, World!";\n return 0;\n}\n</code></pre>\n', '\n###代码\n```javascript\n#include <iostream>\nusing namespace std;\n \nint main() \n{\n cout << "Hello, World!";\n return 0;\n}\n```', '0124961ae4b44758b62f69c2e87c1ad8', '0124961ae4b44758b62f69c2e87c1ad8.png', '2020-06-08 14:10:28', 14, 1),
('03bc94ac5fd5431f8884c836f9cdab8b', 1000000, 'Google浏览器安装包', 'Google 谷歌 浏览器', '<p><strong>Google Chrome</strong>是由Google开发的免费网页浏览器[9]。Chrome是化学元素“铬”的英文名称,过去也用Chrome称呼浏览器的外框[10][11][12][13]。Chrome相应的开放源代码计划名为Chromium[14][15],而Google Chrome本身是非自由软件,未开放全部源代码[9][16]。</p>\n<p>Chrome代码是基于其他开放源代码软件所编写,包括Apple WebKit和Mozilla Firefox,并开发出称为“V8”的高性能JavaScript引擎[17]。Google Chrome的整体发展目标是提升稳定性、速度和安全性,并创造出简单且有效率的用户界面[18]。CNET旗下的Download.com网站评出的2008年6月最佳Windows应用程序,其中Google Chrome排名首位[19]。</p>\n<p>据StatCounter统计,截至2020年1月,Google Chrome在全球桌面浏览器中有69.89%的占有率[20]。</p>\n<p>Chrome 50结束了对Windows XP与Windows Vista系统的支持[21],这两个系统上的最后版本为49.0.2623.112[22]。</p>\n', '**Google Chrome**是由Google开发的免费网页浏览器[9]。Chrome是化学元素“铬”的英文名称,过去也用Chrome称呼浏览器的外框[10][11][12][13]。Chrome相应的开放源代码计划名为Chromium[14][15],而Google Chrome本身是非自由软件,未开放全部源代码[9][16]。\n\nChrome代码是基于其他开放源代码软件所编写,包括Apple WebKit和Mozilla Firefox,并开发出称为“V8”的高性能JavaScript引擎[17]。Google Chrome的整体发展目标是提升稳定性、速度和安全性,并创造出简单且有效率的用户界面[18]。CNET旗下的Download.com网站评出的2008年6月最佳Windows应用程序,其中Google Chrome排名首位[19]。\n\n据StatCounter统计,截至2020年1月,Google Chrome在全球桌面浏览器中有69.89%的占有率[20]。\n\nChrome 50结束了对Windows XP与Windows Vista系统的支持[21],这两个系统上的最后版本为49.0.2623.112[22]。', '03bc94ac5fd5431f8884c836f9cdab8b', '03bc94ac5fd5431f8884c836f9cdab8b.jpg', '2020-06-06 18:46:32', 1, 3),
('138a252e262343e091666d2275aade5e', 1000000, 'C++新标准11/14入门', 'C++ 新标准 11/14', '<h2 id="-">引言</h2>\n<p>C++ 算是一个用户群体比较大的语言了,从 C++98 到 C++11 经历了长达十年多之久的积累,C++14 则是作为对 C++11 的重要补充和优化,所有这些新标准中扩充的特性,给 C++ 这门语言注入了新的活力。</p>\n<p>那些还在坚持使用传统 C++ (本教程把 C++98 及其之前的 C++ 特性均称之为传统 C++)而未接触过 C++11/14 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性时,甚至会流露出『学的不是同一门语言』的惊叹之情。</p>\n<p>C++1x (本教程中指 C++11/14, 甚至 C++17) 为传统 C++ 注入的大量特性使得整个 C++ 变得更加像一门现代化的语言。C++1x 不仅仅增强了 C++ 语言自身的可用性,auto 关键字语义的修改使得我们更加有信心来操控极度复杂的模板类型。同时还对语言运行期进行了大量的强化,Lambda 表达式的出现让 C++ 具有了『匿名函数』的『闭包』特性,而这一特性几乎在现代的编程语言(诸如 Python/Swift/... )中已经司空见惯,右值引用的出现解决了 C++ 长期以来被人诟病的临时对象效率问题等等。</p>\n<p>C++1x 为自身的标准库增加了非常多的工具和方法,诸如在语言层面上提供了 std::thread 支持了并发编程,在不同平台上不再依赖于系统底层的 API,实现了语言层面的跨平台支持;std::regex提供了完整的正则表达式支持等等。</p>\n<p>C++98 已经被实践证明了是一种非常成功的『范型』,而 C++1x 的出现,则进一步推动这种范型,让 C++ 成为系统程序设计和库开发更好的语言。</p>\n<h2 id="-">被弃用的特性</h2>\n<p>在学习 C++1x 之前,我们先了解一下从 C++11 开始,被弃用的主要特性:</p>\n<p>注意:弃用不等于废弃,只是用于暗示程序员这些特性将从未来的标准中消失,应该尽量避免使用。但是,已弃用的特性依然是标准库的一部分,并且出于兼容性的考虑,这些特性其实会『永久』保留。</p>\n<p>如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。</p>\n<p>不再允许字符串字面值常量赋值给一个 char <em>。如果需要用字符串字面值常量赋值和初始化一个 char </em>,应该使用 const char * 或者 auto。</p>\n<p>char *str = "hello world!"; // 将出现弃用警告\nC++98 异常说明、 unexcepted_handler、set_unexpected() 等相关特性被弃用,应该使用 noexcept。</p>\n<p>auto_ptr 被弃用,应使用 unique_ptr。</p>\n<p>register 关键字被弃用。</p>\n<p>bool 类型的 ++ 操作被弃用。</p>\n<p>C 语言风格的类型转换被弃用,应该使用 static_cast、reinterpret_cast、const_cast 来进行类型转换。</p>\n<p>还有一些其他诸如参数绑定(C++11 提供了 std::bind 和 std::function)、export 等特性也均被弃用。前面提到的这些特性如果你从未使用或者听说过,也请不要尝试去了解他们,应该向新标准靠拢,直接学习新特性。毕竟,技术是向前发展的。</p>\n', '##引言\n\nC++ 算是一个用户群体比较大的语言了,从 C++98 到 C++11 经历了长达十年多之久的积累,C++14 则是作为对 C++11 的重要补充和优化,所有这些新标准中扩充的特性,给 C++ 这门语言注入了新的活力。\n\n那些还在坚持使用传统 C++ (本教程把 C++98 及其之前的 C++ 特性均称之为传统 C++)而未接触过 C++11/14 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性时,甚至会流露出『学的不是同一门语言』的惊叹之情。\n\nC++1x (本教程中指 C++11/14, 甚至 C++17) 为传统 C++ 注入的大量特性使得整个 C++ 变得更加像一门现代化的语言。C++1x 不仅仅增强了 C++ 语言自身的可用性,auto 关键字语义的修改使得我们更加有信心来操控极度复杂的模板类型。同时还对语言运行期进行了大量的强化,Lambda 表达式的出现让 C++ 具有了『匿名函数』的『闭包』特性,而这一特性几乎在现代的编程语言(诸如 Python/Swift/... )中已经司空见惯,右值引用的出现解决了 C++ 长期以来被人诟病的临时对象效率问题等等。\n\nC++1x 为自身的标准库增加了非常多的工具和方法,诸如在语言层面上提供了 std::thread 支持了并发编程,在不同平台上不再依赖于系统底层的 API,实现了语言层面的跨平台支持;std::regex提供了完整的正则表达式支持等等。\n\nC++98 已经被实践证明了是一种非常成功的『范型』,而 C++1x 的出现,则进一步推动这种范型,让 C++ 成为系统程序设计和库开发更好的语言。\n\n##被弃用的特性\n在学习 C++1x 之前,我们先了解一下从 C++11 开始,被弃用的主要特性:\n\n注意:弃用不等于废弃,只是用于暗示程序员这些特性将从未来的标准中消失,应该尽量避免使用。但是,已弃用的特性依然是标准库的一部分,并且出于兼容性的考虑,这些特性其实会『永久』保留。\n\n如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。\n\n不再允许字符串字面值常量赋值给一个 char *。如果需要用字符串字面值常量赋值和初始化一个 char *,应该使用 const char * 或者 auto。\n\nchar *str = "hello world!"; // 将出现弃用警告\nC++98 异常说明、 unexcepted_handler、set_unexpected() 等相关特性被弃用,应该使用 noexcept。\n\nauto_ptr 被弃用,应使用 unique_ptr。\n\nregister 关键字被弃用。\n\nbool 类型的 ++ 操作被弃用。\n\nC 语言风格的类型转换被弃用,应该使用 static_cast、reinterpret_cast、const_cast 来进行类型转换。\n\n还有一些其他诸如参数绑定(C++11 提供了 std::bind 和 std::function)、export 等特性也均被弃用。前面提到的这些特性如果你从未使用或者听说过,也请不要尝试去了解他们,应该向新标准靠拢,直接学习新特性。毕竟,技术是向前发展的。', '138a252e262343e091666d2275aade5e', '138a252e262343e091666d2275aade5e.jpg', '2020-06-03 09:22:32', 5, 1),
('179b6916fc574c199d3799634a0f8f6b', 1000002, 'Bool类型关键字', 'Bool 关键字 C++', '<p>标准c++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态。这三个名字都是关键字。</p>\n<p>bool类型只有两个值,true(1值),false(0值)</p>\n<p>bool类型占1个字节大小</p>\n<p>给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)</p>\n<p>[c语言中的bool类型]</p>\n<p>c语言中也有bool类型,在c99标准之前是没有bool关键字,c99标准已经有bool类型,包含头文件stdbool.h,就可以使用和c++一样的bool类型。</p>\n<p>void test()\n{ cout << sizeof(false) << endl; //为1,//bool类型占一个字节大小\n bool flag = true; // c语言中没有这种类型\n flag = 100; //给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)\n}</p>\n', '标准c++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态。这三个名字都是关键字。\n\nbool类型只有两个值,true(1值),false(0值)\n\nbool类型占1个字节大小\n\n给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)\n\n \n\n[c语言中的bool类型]\n\nc语言中也有bool类型,在c99标准之前是没有bool关键字,c99标准已经有bool类型,包含头文件stdbool.h,就可以使用和c++一样的bool类型。\n\nvoid test()\n{ cout << sizeof(false) << endl; //为1,//bool类型占一个字节大小\n bool flag = true; // c语言中没有这种类型\n flag = 100; //给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)\n}', '179b6916fc574c199d3799634a0f8f6b', '179b6916fc574c199d3799634a0f8f6b.jpg', '2020-06-08 13:41:58', 0, 1),
('1a052e12c73c442fb1116d24edd7b5e0', 1000002, 'C++典型错误案例', '典型 错误 案例', '<p>错误类型</p>\n<p>具体表现</p>\n<p>备注(案例)</p>\n<p>声明错误</p>\n<p>变量未声明</p>\n<p>编译时错误</p>\n<p>初始化错误</p>\n<p>未初始化或初始化错误</p>\n<p>运行不正确</p>\n<p>访问错误</p>\n<p>1、 数组索引访问越界</p>\n<p>2、 指针对象访问越界</p>\n<p>3、 访问空指针对象</p>\n<p>4、 访问无效指针对象</p>\n<p>5、 迭代器访问越界</p>\n<p>内存泄漏</p>\n<p>1、 内存未释放</p>\n<p>2、 内存局部释放</p>\n<p>参数错误</p>\n<p>本地代理、空指针、强制转换</p>\n<p>堆栈溢出</p>\n<p>调用堆栈溢出:</p>\n<p>1、递归调用</p>\n<p>2、循环调用</p>\n<p>3、消息循环</p>\n<p>4、大对象参数</p>\n<p>5、大对象变量</p>\n<p>参数、局部变量都在栈(Stack)上分配</p>\n<p>转换错误</p>\n<p>有符号类型和无符号类型转换</p>\n<p>内存碎片</p>\n<p>小内存块重复分配释放导致的内存碎片,最后出现内存不足</p>\n<p>数据对齐,机器字整数倍分配</p>\n', '错误类型\n\n具体表现\n\n备注(案例)\n\n声明错误\n\n变量未声明\n\n编译时错误\n\n初始化错误\n\n未初始化或初始化错误\n\n运行不正确\n\n访问错误\n\n1、 数组索引访问越界\n\n2、 指针对象访问越界\n\n3、 访问空指针对象\n\n4、 访问无效指针对象\n\n5、 迭代器访问越界\n\n \n\n内存泄漏\n\n1、 内存未释放\n\n2、 内存局部释放\n\n \n\n参数错误\n\n本地代理、空指针、强制转换\n\n \n\n堆栈溢出\n\n调用堆栈溢出:\n\n1、递归调用\n\n2、循环调用\n\n3、消息循环\n\n4、大对象参数\n\n5、大对象变量\n\n参数、局部变量都在栈(Stack)上分配\n\n转换错误\n\n有符号类型和无符号类型转换\n\n \n\n内存碎片\n\n小内存块重复分配释放导致的内存碎片,最后出现内存不足\n\n数据对齐,机器字整数倍分配', '1a052e12c73c442fb1116d24edd7b5e0', '1a052e12c73c442fb1116d24edd7b5e0.jpg', '2020-06-08 13:30:04', 1, 1),
('1f1e50aaeb4945f4ba8c2f9eb6ab0a89', 1000002, 'C++吃豆豆游戏开发', '吃豆豆 游戏 开发 ', '<p>《吃豆人》(日语:パックマン,英语:Pac-Man,中国大陆译作“吃豆人”,香港译作“食鬼”,台湾译作“小精靈”,中国大陆又译作「吃豆子」)是一款由南梦宫公司制作的街机游戏。游戏最初于1980年5月22日在日本发行。本游戏由南梦宫公司的岩谷徹設計。游戏于1980年10月由Midway Games公司在美国发行[1]。缺了一角的薄餅是岩谷徹創作此遊戲的靈感來源[2]。</p>\n<p>Pac-Man在1980年代風靡全球,被认为是最经典的街机游戏之一,游戏的主角小精靈的形象甚至被作为一种大众文化符号,或是電子遊戲产业的代表形象。它的开发商Namco也把这个形象作为其吉祥物和公司的标志,一直沿用至今。亦因爲該遊戲風靡全球,幪面超人系列在2016年上映的電影《假面騎士平成Generations Dr.Pac-Man對EX-AID&Ghost with 傳說騎士》首次與遊戲角色食鬼合作。</p>\n<p>游戏模式</p>\n<p>游戏的目的就是控制游戏的主角小精靈吃掉藏在迷宫内所有的豆子,并且不能被鬼魂抓到。</p>\n<p>迷宮的四個角落有大的閃爍點稱為大力丸,提供小精靈一小段時間,可以反過來吃掉鬼魂的力量。鬼魂在這段時間內會變成深藍色,會往反方向逃逸,而且比平常的移動速度慢。有趣的是,當鬼魂被吃掉時,它的眼睛還在,會飛回鬼屋,並再生而恢复正常的顏色。當深藍色的鬼魂反白閃動時,表示大力丸的效力即將消失,而隨著遊戲的進展,大力丸的有效時間會越來越短。在遊戲的後段,大力丸被吃掉時,鬼魂不會改變顏色,但仍會往相反方向逃。</p>\n', '《吃豆人》(日语:パックマン,英语:Pac-Man,中国大陆译作“吃豆人”,香港译作“食鬼”,台湾译作“小精靈”,中国大陆又译作「吃豆子」)是一款由南梦宫公司制作的街机游戏。游戏最初于1980年5月22日在日本发行。本游戏由南梦宫公司的岩谷徹設計。游戏于1980年10月由Midway Games公司在美国发行[1]。缺了一角的薄餅是岩谷徹創作此遊戲的靈感來源[2]。\n\nPac-Man在1980年代風靡全球,被认为是最经典的街机游戏之一,游戏的主角小精靈的形象甚至被作为一种大众文化符号,或是電子遊戲产业的代表形象。它的开发商Namco也把这个形象作为其吉祥物和公司的标志,一直沿用至今。亦因爲該遊戲風靡全球,幪面超人系列在2016年上映的電影《假面騎士平成Generations Dr.Pac-Man對EX-AID&Ghost with 傳說騎士》首次與遊戲角色食鬼合作。\n\n游戏模式\n\n游戏的目的就是控制游戏的主角小精靈吃掉藏在迷宫内所有的豆子,并且不能被鬼魂抓到。\n\n迷宮的四個角落有大的閃爍點稱為大力丸,提供小精靈一小段時間,可以反過來吃掉鬼魂的力量。鬼魂在這段時間內會變成深藍色,會往反方向逃逸,而且比平常的移動速度慢。有趣的是,當鬼魂被吃掉時,它的眼睛還在,會飛回鬼屋,並再生而恢复正常的顏色。當深藍色的鬼魂反白閃動時,表示大力丸的效力即將消失,而隨著遊戲的進展,大力丸的有效時間會越來越短。在遊戲的後段,大力丸被吃掉時,鬼魂不會改變顏色,但仍會往相反方向逃。', '1f1e50aaeb4945f4ba8c2f9eb6ab0a89', '1f1e50aaeb4945f4ba8c2f9eb6ab0a89.png', '2020-06-08 14:12:58', 0, 1),
('2bcfdbe8dc414a259b81dd5a95a75f0f', 1000002, 'C中的冒牌货', 'C 冒牌货 const', '<pre><code class="lang-javascript">#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint main()\n{\n const int a = 10;\n // C语言中能够通过指针间接修改,const已经发挥不到它的作用\n // C++中这样会报错,需要加const int* p = &a; 不能通过p间接修改\n int* p = &a;\n *p = 20;\n printf("a = %d\\n", a);\n\n}\n</code></pre>\n<p>————————————————\n版权声明:本文为CSDN博主「幻欢子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。\n原文链接:<a href="https://blog.csdn.net/u012424148/java/article/details/100026313">https://blog.csdn.net/u012424148/java/article/details/100026313</a></p>\n', '\n\n```javascript\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n \nint main()\n{\n const int a = 10;\n // C语言中能够通过指针间接修改,const已经发挥不到它的作用\n // C++中这样会报错,需要加const int* p = &a; 不能通过p间接修改\n int* p = &a;\n *p = 20;\n printf("a = %d\\n", a);\n \n}\n\n```\n————————————————\n版权声明:本文为CSDN博主「幻欢子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。\n原文链接:https://blog.csdn.net/u012424148/java/article/details/100026313', '2bcfdbe8dc414a259b81dd5a95a75f0f', '2bcfdbe8dc414a259b81dd5a95a75f0f.png', '2020-06-08 13:22:54', 2, 1),
('33dd5a30ad87497888527fbb7c8f6b4f', 1000002, 'C++ 命名空间', '命名空间 namespace', '<p>C++ 命名空间\n假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字等等。</p>\n<p>同样的情况也出现在 C++ 应用程序中。例如,您可能会写一个名为 xyz() 的函数,在另一个可用的库中也存在一个相同的函数 xyz()。这样,编译器就无法判断您所使用的是哪一个 xyz() 函数。</p>\n<p>因此,引入了命名空间这个概念,专门用于解决上面的问题,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。</p>\n<p>定义命名空间\n命名空间的定义使用关键字 namespace,后跟命名空间的名称,如下所示:</p>\n<pre><code class="lang-javascript">namespace namespace_name {\n // 代码声明\n}\n</code></pre>\n<p>为了调用带有命名空间的函数或变量,需要在前面加上命名空间的名称,如下所示:</p>\n<pre><code class="lang-javascript">name::code; // code 可以是变量或函数\n</code></pre>\n<p>让我们来看看命名空间如何为变量或函数等实体定义范围:</p>\n<pre><code class="lang-javascript">#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n}\n// 第二个命名空间\nnamespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n}\nint main ()\n{\n\n // 调用第一个命名空间中的函数\n first_space::func();\n\n // 调用第二个命名空间中的函数\n second_space::func(); \n\n return 0;\n}\n</code></pre>\n<p>当上面的代码被编译和执行时,它会产生下列结果:</p>\n<p>Inside first_space\nInside second_space\nusing 指令\n您可以使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。</p>\n<pre><code class="lang-javascript">#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n}\n// 第二个命名空间\nnamespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n}\nusing namespace first_space;\nint main ()\n{\n\n // 调用第一个命名空间中的函数\n func();\n\n return 0;\n}\n</code></pre>\n<p>当上面的代码被编译和执行时,它会产生下列结果:</p>\n<p>Inside first_space\nusing 指令也可以用来指定命名空间中的特定项目。例如,如果您只打算使用 std 命名空间中的 cout 部分,您可以使用如下的语句:</p>\n<p>using std::cout;\n随后的代码中,在使用 cout 时就可以不用加上命名空间名称作为前缀,但是 std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀,如下所示:</p>\n<pre><code class="lang-javascript">#include <iostream>\nusing std::cout;\n\nint main ()\n{\n\n cout << "std::endl is used with std!" << std::endl;\n\n return 0;\n}\n</code></pre>\n<p>当上面的代码被编译和执行时,它会产生下列结果:</p>\n<p>std::endl is used with std!\nusing 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的,直到该范围结束。此时,在范围以外定义的同名实体是隐藏的。</p>\n<p>不连续的命名空间\n命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。</p>\n<p>所以,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素:</p>\n<pre><code class="lang-javascript">namespace namespace_name {\n // 代码声明\n}\n</code></pre>\n<p>嵌套的命名空间\n命名空间可以嵌套,您可以在一个命名空间中定义另一个命名空间,如下所示:</p>\n<pre><code class="lang-javascript">namespace namespace_name1 {\n // 代码声明\n namespace namespace_name2 {\n // 代码声明\n }\n}\n</code></pre>\n<p>您可以通过使用 :: 运算符来访问嵌套的命名空间中的成员:</p>\n<p>// 访问 namespace_name2 中的成员\nusing namespace namespace_name1::namespace_name2;</p>\n<p>// 访问 namespace:name1 中的成员\nusing namespace namespace_name1;\n在上面的语句中,如果使用的是 namespace_name1,那么在该范围内 namespace_name2 中的元素也是可用的,如下所示:</p>\n<pre><code class="lang-javascript">#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n // 第二个命名空间\n namespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n }\n}\nusing namespace first_space::second_space;\nint main ()\n{\n\n // 调用第二个命名空间中的函数\n func();\n\n return 0;\n}\n</code></pre>\n<p>当上面的代码被编译和执行时,它会产生下列结果:</p>\n<pre><code class="lang-javascript">Inside second_space\n</code></pre>\n', 'C++ 命名空间\n假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字等等。\n\n同样的情况也出现在 C++ 应用程序中。例如,您可能会写一个名为 xyz() 的函数,在另一个可用的库中也存在一个相同的函数 xyz()。这样,编译器就无法判断您所使用的是哪一个 xyz() 函数。\n\n因此,引入了命名空间这个概念,专门用于解决上面的问题,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。\n\n定义命名空间\n命名空间的定义使用关键字 namespace,后跟命名空间的名称,如下所示:\n\n\n\n```javascript\nnamespace namespace_name {\n // 代码声明\n}\n```\n为了调用带有命名空间的函数或变量,需要在前面加上命名空间的名称,如下所示:\n\n\n\n```javascript\nname::code; // code 可以是变量或函数\n```\n让我们来看看命名空间如何为变量或函数等实体定义范围:\n\n\n\n```javascript\n#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n}\n// 第二个命名空间\nnamespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n}\nint main ()\n{\n \n // 调用第一个命名空间中的函数\n first_space::func();\n \n // 调用第二个命名空间中的函数\n second_space::func(); \n\n return 0;\n}\n```\n当上面的代码被编译和执行时,它会产生下列结果:\n\nInside first_space\nInside second_space\nusing 指令\n您可以使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。\n\n\n\n```javascript\n#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n}\n// 第二个命名空间\nnamespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n}\nusing namespace first_space;\nint main ()\n{\n \n // 调用第一个命名空间中的函数\n func();\n \n return 0;\n}\n```\n当上面的代码被编译和执行时,它会产生下列结果:\n\nInside first_space\nusing 指令也可以用来指定命名空间中的特定项目。例如,如果您只打算使用 std 命名空间中的 cout 部分,您可以使用如下的语句:\n\nusing std::cout;\n随后的代码中,在使用 cout 时就可以不用加上命名空间名称作为前缀,但是 std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀,如下所示:\n\n\n\n```javascript\n#include <iostream>\nusing std::cout;\n\nint main ()\n{\n \n cout << "std::endl is used with std!" << std::endl;\n \n return 0;\n}\n```\n当上面的代码被编译和执行时,它会产生下列结果:\n\nstd::endl is used with std!\nusing 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的,直到该范围结束。此时,在范围以外定义的同名实体是隐藏的。\n\n不连续的命名空间\n命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。\n\n所以,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素:\n\n\n\n```javascript\nnamespace namespace_name {\n // 代码声明\n}\n```\n嵌套的命名空间\n命名空间可以嵌套,您可以在一个命名空间中定义另一个命名空间,如下所示:\n\n\n\n```javascript\nnamespace namespace_name1 {\n // 代码声明\n namespace namespace_name2 {\n // 代码声明\n }\n}\n```\n您可以通过使用 :: 运算符来访问嵌套的命名空间中的成员:\n\n// 访问 namespace_name2 中的成员\nusing namespace namespace_name1::namespace_name2;\n\n// 访问 namespace:name1 中的成员\nusing namespace namespace_name1;\n在上面的语句中,如果使用的是 namespace_name1,那么在该范围内 namespace_name2 中的元素也是可用的,如下所示:\n\n\n\n```javascript\n#include <iostream>\nusing namespace std;\n\n// 第一个命名空间\nnamespace first_space{\n void func(){\n cout << "Inside first_space" << endl;\n }\n // 第二个命名空间\n namespace second_space{\n void func(){\n cout << "Inside second_space" << endl;\n }\n }\n}\nusing namespace first_space::second_space;\nint main ()\n{\n \n // 调用第二个命名空间中的函数\n func();\n \n return 0;\n}\n```\n当上面的代码被编译和执行时,它会产生下列结果:\n\n\n\n```javascript\nInside second_space\n```', NULL, NULL, '2020-06-08 14:34:14', 0, 2),
('33fd0cd85efa41a1808ac4687d1e7424', 1000000, 'C++纯代码音乐代码项目', 'C++ 代码 音乐', '<h1 id="-">部分代码</h1>\n<pre><code class="lang-javascript">\n#include <Windows.h>\n#include <conio.h>\n#include <stdio.h>\n#include <locale.h>\n#include <math.h>\n\n#pragma comment(lib, "winmm")\n\n// A-G 代表低音 1-7\n// H-N 代表中音 1-7\n// O-U 代表高音 1-7\n\n// 音乐乐谱结构体\nstruct MUSIC\n{\n // 标题\n const char *title;\n // 内容\n const char *content;\n};\n\n// 音乐乐谱列表\nconst MUSIC musics[] = {\n {\n "生日快乐",\n "EEFEHG\\n"\n "EEFEIH\\n"\n "EELJHGF\\n"\n "KKJHIH\\n"\n },\n {\n "小星星",\n "HHLLMML KKJJIIH\\n"\n "LLKKJJI LLKKJJI\\n"\n "HHLLMML KKJJIIH\\n"\n },\n {\n "欢乐颂",\n "JJKLLKJI HHIJJII\\n"\n "JJKLLKJI HHIJIHH\\n"\n "IIJHIJKJ HIJKJIHIE\\n"\n "JJKLLKJI HHIJIHH\\n"\n },\n {\n "天空之城",\n "MNONOQN LJMLMOLL\\n"\n "KJKOJ JHOON OONNMN\\n"\n "ONOQN JMLMHLJ\\n"\n "JKONOPQOO ONMMNLM\\n"\n "OPQPQSP LONOQQ\\n"\n "MNOONOPO LLRQPOQ\\n"\n "QTSQPO POPSQ\\n"\n "QTSQPO POPNM\\n"\n "MNONOQN JMLMHLJ\\n"\n },\n {\n "梁祝",\n "LJIH IGFE\\n"\n "NMNLMKJL IJLIJKJIH\\n"\n "LGIFHE FHE\\n"\n "CEFHI FHE\\n"\n "LOMLJLI\\n"\n "IJGFEFHICHFEFHE\\n"\n "JLGIFHE CECEFGIF\\n"\n "EFHILJIJIHFECH FHFECEFHE\\n"\n "JLIJIHGFE\\n"\n },\n {\n "北京欢迎你",\n "QSQPQPQ QPMOQP\\n"\n "POMOPQSPQTSSPO\\n"\n "POMOPQSPQTSSQ\\n"\n "PQPOSTQ MQPPO\\n"\n "QSVST TSQQSS\\n"\n "QSTVWVSQPSQQ\\n"\n "QSVST VWVSQSVT\\n"\n "QPQSXW VV\\n"\n },\n {\n "菊花台",\n "JJIJ JLJIJ HHIJLJ IIHI\\n"\n "J LJML MLLJL EJIILJIIIHI\\n"\n "JJIJ JLJIJ HHIJLJ IIHI\\n"\n "J LJML MLLJL JIJLJIIH\\n"\n "HIJ JLM MQQPOML MLJIH FHIIHI\\n"\n "HIJ JLM MQPOOPO LLJNOHIJ IH\\n"\n },\n {\n "青花瓷",\n "LLJIJF IJLJI\\n"\n "LLJIJE IJLIH\\n"\n "HIJLMLJLJJII\\n"\n "HIHIHIIJLJJ\\n"\n "LLJIJF IJLJI\\n"\n "LLJIJE IJLIH\\n"\n "HIJLMLJLJJII\\n"\n "EJIIH\\n"\n },\n {\n "红豆",\n "LMPOPOP LMPOPQP LMPOOMPQPO POOML\\n"\n "LMPOPOP LMPOPQP LMPOOMPQPO TSSQP\\n"\n "OPS OPQ QPPOQVUTQ UTST TSRS QPOQP OMQPP\\n"\n "OPS OPQ QPPOQVUVT TXWUSQT QPOP TTSPPQ POO\\n"\n },\n {\n "分手快乐",\n "EHHHGHE FGHIHGGH\\n"\n "EHGHHHE FGHIKJHI\\n"\n "IIIKJIG HHHHIGH\\n"\n "HIJFHHHHE EHJKJIHGHI\\n"\n "EHHHGHE FGHIHGGHH\\n"\n "EHGHHHE FGHIKJHII\\n"\n "IIIKJIG HHHHIGH\\n"\n "HIJKJIH HLJIH\\n"\n "EFHHHF FKJHIJI\\n"\n "HHIJ HHIJ LJGHHHGH\\n"\n "HHIJ HHIJ LJHIIIHFJI\\n"\n "HHIJ HHIJ LLJGHHHHGIH\\n"\n "HHIJ HHIJ LLJHIIIIKJI\\n"\n "JKJHHFGHIJ\\n"\n "JJKLKJHILH\\n"\n "JJKLKJHILH\\n"\n },\n {\n "童话",\n "LONOL LONOL LONO OOMML\\n"\n "LONOL LQPPO LONOM MMOTS\\n"\n "PPRRQQ QQNPOONO ONOR LSRQP\\n"\n "PPRRQQ QQVUTUV VPOT TTSSS\\n"\n "LSRQ QRQ QRQRQPO OQST TTSPPRQ\\n"\n "OQST TTSPPRQRQPO PQM MOO NO\\n"\n },\n {\n "美丽的神话",\n "MQN MOPOQ MTSTSPRQ\\n"\n "MTSPQRQ O MQPNM\\n"\n "MQNMOPOQ MTSTSPRQ\\n"\n "MTSPQRQPO MPONM\\n"\n "MNOPQONL MOPQQ\\n"\n "MNOPQONLMOPOO MPONM\\n"\n "MNOPQONL MOPQQ\\n"\n "MNOPQONLMOPOO OOPQONLONMNT\\n"\n },\n {\n "虫儿飞",\n "JJJKLJII HHHIJJGG FJI FJI FJIHH\\n"\n "JJJKLJII HHHIJJGG FJI FJI FJIHH \\n"\n "JIL KJI LKJKLJI HFJI HFIH KJKJH HKJKJHIH\\n"\n },\n {\n "大海",\n "FEHHHH EFHHIH FHIIII HFIIJI\\n"\n "JLMMLM LJIJIHF EFHHHHIH\\n"\n "JLMMMMOMLLML JIHHHHIJ\\n"\n "JIHHHHOMLLML JLMOOML\\n"\n "JLMMMMOMLLML JIHHHHLJ\\n"\n "JIHHHHIJLLJL JLM FJIHH\\n"\n },\n {\n "梦中的婚礼",\n "MMNNOONNMMJJHHFFLLKKJKLK\\n"\n "KKLLMMNNLLIIKKJJIIKJ\\n"\n "JFHJIJ FHJIJ FHKJK FHKJK KJKKLLMLMJ\\n"\n "QMOQPQ MOQPQ MORQR MORQR RQRRSSTSTQ\\n"\n "O JJKKIINN IIJJ HHMLM HHII GJIJ\\n"\n "O OOPPONML LMLJ O OOPPONML LMLM\\n"\n },\n {\n "致爱丽斯",\n "QPQPQNPOM HJMNJLNOJ\\n"\n "QPQPQNPOM HJMNJONM\\n"\n "NOPQLRQPKQPOJPON\\n"\n "NJQQQQPQPQNPOM HJMNJLNOJ\\n"\n "QPQPQNPOM HJMNJONM\\n"\n "ORQQPPRTSRQPONMMLMNOPPQRMOPNOPQSPNOPQSPNQQQQQP\\n"\n },\n};\n</code></pre>\n', '#部分代码\n\n```javascript\n\n#include <Windows.h>\n#include <conio.h>\n#include <stdio.h>\n#include <locale.h>\n#include <math.h>\n\n#pragma comment(lib, "winmm")\n\n// A-G 代表低音 1-7\n// H-N 代表中音 1-7\n// O-U 代表高音 1-7\n\n// 音乐乐谱结构体\nstruct MUSIC\n{\n // 标题\n const char *title;\n // 内容\n const char *content;\n};\n\n// 音乐乐谱列表\nconst MUSIC musics[] = {\n {\n "生日快乐",\n "EEFEHG\\n"\n "EEFEIH\\n"\n "EELJHGF\\n"\n "KKJHIH\\n"\n },\n {\n "小星星",\n "HHLLMML KKJJIIH\\n"\n "LLKKJJI LLKKJJI\\n"\n "HHLLMML KKJJIIH\\n"\n },\n {\n "欢乐颂",\n "JJKLLKJI HHIJJII\\n"\n "JJKLLKJI HHIJIHH\\n"\n "IIJHIJKJ HIJKJIHIE\\n"\n "JJKLLKJI HHIJIHH\\n"\n },\n {\n "天空之城",\n "MNONOQN LJMLMOLL\\n"\n "KJKOJ JHOON OONNMN\\n"\n "ONOQN JMLMHLJ\\n"\n "JKONOPQOO ONMMNLM\\n"\n "OPQPQSP LONOQQ\\n"\n "MNOONOPO LLRQPOQ\\n"\n "QTSQPO POPSQ\\n"\n "QTSQPO POPNM\\n"\n "MNONOQN JMLMHLJ\\n"\n },\n {\n "梁祝",\n "LJIH IGFE\\n"\n "NMNLMKJL IJLIJKJIH\\n"\n "LGIFHE FHE\\n"\n "CEFHI FHE\\n"\n "LOMLJLI\\n"\n "IJGFEFHICHFEFHE\\n"\n "JLGIFHE CECEFGIF\\n"\n "EFHILJIJIHFECH FHFECEFHE\\n"\n "JLIJIHGFE\\n"\n },\n {\n "北京欢迎你",\n "QSQPQPQ QPMOQP\\n"\n "POMOPQSPQTSSPO\\n"\n "POMOPQSPQTSSQ\\n"\n "PQPOSTQ MQPPO\\n"\n "QSVST TSQQSS\\n"\n "QSTVWVSQPSQQ\\n"\n "QSVST VWVSQSVT\\n"\n "QPQSXW VV\\n"\n },\n {\n "菊花台",\n "JJIJ JLJIJ HHIJLJ IIHI\\n"\n "J LJML MLLJL EJIILJIIIHI\\n"\n "JJIJ JLJIJ HHIJLJ IIHI\\n"\n "J LJML MLLJL JIJLJIIH\\n"\n "HIJ JLM MQQPOML MLJIH FHIIHI\\n"\n "HIJ JLM MQPOOPO LLJNOHIJ IH\\n"\n },\n {\n "青花瓷",\n "LLJIJF IJLJI\\n"\n "LLJIJE IJLIH\\n"\n "HIJLMLJLJJII\\n"\n "HIHIHIIJLJJ\\n"\n "LLJIJF IJLJI\\n"\n "LLJIJE IJLIH\\n"\n "HIJLMLJLJJII\\n"\n "EJIIH\\n"\n },\n {\n "红豆",\n "LMPOPOP LMPOPQP LMPOOMPQPO POOML\\n"\n "LMPOPOP LMPOPQP LMPOOMPQPO TSSQP\\n"\n "OPS OPQ QPPOQVUTQ UTST TSRS QPOQP OMQPP\\n"\n "OPS OPQ QPPOQVUVT TXWUSQT QPOP TTSPPQ POO\\n"\n },\n {\n "分手快乐",\n "EHHHGHE FGHIHGGH\\n"\n "EHGHHHE FGHIKJHI\\n"\n "IIIKJIG HHHHIGH\\n"\n "HIJFHHHHE EHJKJIHGHI\\n"\n "EHHHGHE FGHIHGGHH\\n"\n "EHGHHHE FGHIKJHII\\n"\n "IIIKJIG HHHHIGH\\n"\n "HIJKJIH HLJIH\\n"\n "EFHHHF FKJHIJI\\n"\n "HHIJ HHIJ LJGHHHGH\\n"\n "HHIJ HHIJ LJHIIIHFJI\\n"\n "HHIJ HHIJ LLJGHHHHGIH\\n"\n "HHIJ HHIJ LLJHIIIIKJI\\n"\n "JKJHHFGHIJ\\n"\n "JJKLKJHILH\\n"\n "JJKLKJHILH\\n"\n },\n {\n "童话",\n "LONOL LONOL LONO OOMML\\n"\n "LONOL LQPPO LONOM MMOTS\\n"\n "PPRRQQ QQNPOONO ONOR LSRQP\\n"\n "PPRRQQ QQVUTUV VPOT TTSSS\\n"\n "LSRQ QRQ QRQRQPO OQST TTSPPRQ\\n"\n "OQST TTSPPRQRQPO PQM MOO NO\\n"\n },\n {\n "美丽的神话",\n "MQN MOPOQ MTSTSPRQ\\n"\n "MTSPQRQ O MQPNM\\n"\n "MQNMOPOQ MTSTSPRQ\\n"\n "MTSPQRQPO MPONM\\n"\n "MNOPQONL MOPQQ\\n"\n "MNOPQONLMOPOO MPONM\\n"\n "MNOPQONL MOPQQ\\n"\n "MNOPQONLMOPOO OOPQONLONMNT\\n"\n },\n {\n "虫儿飞",\n "JJJKLJII HHHIJJGG FJI FJI FJIHH\\n"\n "JJJKLJII HHHIJJGG FJI FJI FJIHH \\n"\n "JIL KJI LKJKLJI HFJI HFIH KJKJH HKJKJHIH\\n"\n },\n {\n "大海",\n "FEHHHH EFHHIH FHIIII HFIIJI\\n"\n "JLMMLM LJIJIHF EFHHHHIH\\n"\n "JLMMMMOMLLML JIHHHHIJ\\n"\n "JIHHHHOMLLML JLMOOML\\n"\n "JLMMMMOMLLML JIHHHHLJ\\n"\n "JIHHHHIJLLJL JLM FJIHH\\n"\n },\n {\n "梦中的婚礼",\n "MMNNOONNMMJJHHFFLLKKJKLK\\n"\n "KKLLMMNNLLIIKKJJIIKJ\\n"\n "JFHJIJ FHJIJ FHKJK FHKJK KJKKLLMLMJ\\n"\n "QMOQPQ MOQPQ MORQR MORQR RQRRSSTSTQ\\n"\n "O JJKKIINN IIJJ HHMLM HHII GJIJ\\n"\n "O OOPPONML LMLJ O OOPPONML LMLM\\n"\n },\n {\n "致爱丽斯",\n "QPQPQNPOM HJMNJLNOJ\\n"\n "QPQPQNPOM HJMNJONM\\n"\n "NOPQLRQPKQPOJPON\\n"\n "NJQQQQPQPQNPOM HJMNJLNOJ\\n"\n "QPQPQNPOM HJMNJONM\\n"\n "ORQQPPRTSRQPONMMLMNOPPQRMOPNOPQSPNOPQSPNQQQQQP\\n"\n },\n};\n```', '33fd0cd85efa41a1808ac4687d1e7424', '33fd0cd85efa41a1808ac4687d1e7424.png', '2020-06-06 18:53:30', 0, 6),
('3b3aafd13c7b4aff8eea93f127413fb1', 1000002, '一篇文章让你学会C++', '轻松学习C++', '<p>class 类名\n{\nprivate:\n私有成员数据;\nprotected:\n保护成员;\npublic:\n公用数据和函数;\n};</p>\n<p>::作用域限定符</p>\n<p>inline函数 内联函数\n在函数首行左端加inline\n如果在类体中定义的成员函数中没有循环控制结构,\n编译系统会自动视为inline函数\n类内申明内置成员函数,可以省去inline,类外不能省去</p>\n<p>类的属性:封装性</p>\n<p>用类定义对象时,系统会为每一个对象分配存储空间\n每个对象所占用的存储空间只是对象的数据成员所占用的空间\n不包括函数代码</p>\n<p>引用对象的3中方法\n1通过对象名和成员运算符访问对象中的成员 对象名.成员\n2通过指向对象的指针访问对象中的成员 指针->成员\n3通过对象的引用变量访问对象中的成员 对象引用.成员</p>\n<p>构造函数:特殊的成员函数,专门用来处理对象的初始化,\n1不需要用户调用,自动执行\n2构造函数的名字与类名相同\n3没有函数类型 不返回任何值</p>\n<p>构造函数类型(必须是Public成员)\n默认构造函数(空构造函数)\n不带参数的构造函数\n带参数的构造函数\n函数体传递参数\n通过参数初始化来传递\n指定默认参数</p>\n<p>构造函数重载 参数类型或者个数不同</p>\n<p>析构函数 ~类名</p>\n<p>先构造的后析构</p>\n<p>对象赋值的一般形式:对象名1=对象名2\n对象的拷贝 类名 对象2(对象1) 或者 类名 对象名2 = 对象名1\ne.g. Box box2(box1);\n调用拷贝构造函数\nBox::Box(const Box& b)\n{height = b.height;\nwidth = b.width;\nlength = b.length;}</p>\n<p>构造函数只有一个参数,参数是本类的对象</p>\n<p>对象的隐式复制:在对象作为函数参数或返回值时,会发生隐式复制。但都会调用拷贝构造函数\ntoday = func(today); 其中函数中的对象都是在函数所在这一句执行完之后释放</p>\n<p>浅拷贝:比如struct中有一个变量是地址,这儿时候用 b=a,此时b的那个变量地址\n和a中的相同 这就造成了地址的共享</p>\n<p>对象数组的初始化\n类名 对象名[长度] = { 构造函数(实参列表1),构造函数(实参列表2),...}</p>\n<p>对象指针,可是 用类来定义的 指针,也可以是 志向对象数据成员的指针变量。\n也可以是 指向 对象成员函数的指针\n形式 数据类型 (类名::<em>指针变量名)(参数列表);\ne.g. void (Time::</em>p2) ();\np3 = &Time::get_time;\n(t1.*p3)();</p>\n<p>每个成员函数都包含一个特殊的指针,即this 其值是当前被调用的成员函数所在的对象起始地址</p>\n<p>共用数据的保护\nconst int a =3;\n则a不能改变 const 比 #define 的好处是 const 有类型\nconst 数据类型名 变量名 = 初值表达式;\nconst 数据类型名 <em> 指针变量名; 指向的内存空间不能改变 自身指向地址可以更改\n数据类型名</em> const 指针变量名 = 处置表达式;\n自身内容 指向的地址不可更改的指针变量 常指针</p>\n<p>类名 const 对象名(参数列表);\n自身内容不可更改 不能调用非const成员函数</p>\n<p>const 类名* 指针变量名;\n指向的空间不能更改 自身的指向可以更改</p>\n<p>类名 * const 指针变量名 = 初值表达式;\n指向的地址 不可更改的类指针</p>\n<p>const 类名 & 对象名 = 初值表达式;\n常引用 其值为只读</p>\n<p>const 数据类型名 变量名; 的初始化\n可以通过参数初始化表[注意是表]</p>\n<p>数据类型名 成员函数(参数列表) const;\n声明常成员函数,函数体不能更改类成员函数</p>\n<p>数据类型名 类名::成员函数名(参数列表) const\n{ ... }\n定义常成员函数 ,函数体不能更改 类成员变量</p>\n<p>数据成员 非const成员函数 const成员函数\n非const数据成员 可以引用 也可以改变值 可以引用 但不能改变值\nconst数据成员 可以一用 但不能改变值 可以引用 但不能改变值\nconst对象的数据成员 不允许引用和改变值 可以引用 但不可以改变值</p>\n<p>提高效率 用 引用来传递对象\n常成员函数 = 只读访问接口</p>\n<p>静态数据成员\nstatic int num;\n实现同类对象之间的数据共享</p>\n<p>初始化方式\nInt student::num = 0;\n或者声明一个不属于任何对象的 静态成员函数类专门负责静态常远的初始化\npublic: static void set_default(int d,int m, int y)\n{ default_day.d= d;\ndefault_day.m = m;\ndefault_day.y = y;}</p>\n<p>静态成员实际上是全局变量 在main()函数结束后才释放\n静态成员函数没有this指针</p>\n<p>运算符 重载\n函数类型 operator 运算符名称呢过(形参列表)\n{ 对运算符虫子啊处理的函数体}</p>\n<p>Complex operator+ (Complex& c1, Complex& c2);</p>\n<p>不能重载的运算符 . .* :: sizeof ?:</p>\n<p>Complex & operator + (Complex & c2);\nComplex & operator * (float c2);\nComplex & operator = (Complex & c2);\nComplex & operator > (Complex & c2);\n单目运算符\nComplex & operator ! ();\nComplex & operator + ();\nComplex & operator ++ ();\nComplex & operator () ();</p>\n<p>前置自增\nDate operator ++()\n后置自增\nDate &operator ++ (int)</p>\n<p>友元函数\nfriend void Print(const Date& D);\nfriend 函数类型 operator 运算符名称(参数列表);\n<< >> 不能够重载为成员函数 = [] () 不能重载为友元函数</p>\n<p>将其他类的尘缘函数声明为类的有缘\n如果一个类A 是类B 的 子类, 那么可以在A中声明一个B的函数为友元函数\nfriend Student::Print();\nfriend B::Print();</p>\n<p>将类声明为类的友元\n如\nclass Date\n{\nfriend Student;\n};\nclass Student\n{\nDate birthday;\npublic:\nvoid Print();\nvoid Copy();\n};\n这个时候 Student的成员函数可以访问birtday的私有成员</p>\n<p>friend ostream& operator<< (ostream&,Complex&);\n在类外\nostream& operator<<(ostream& output, Complex& c)\n{output<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;\nreturn output;}</p>\n<p>转换构造函数\nComplex(double r) { real = r; imag = i; }</p>\n<p>派生的一般形式\nclass 派生类名:[继承方式] 基类名\n{ 新增加的成员 };</p>\n<p>继承性质 基类中丰源访问权限 派生类中成员的访问权限\nPublic Public Public\nprotected protected\nprivate 不可访问</p>\n<p>protected Public protected\nprotected protected\nprivate 不可访问</p>\n<p>private public private\nprotected private\nprivate 不可访问</p>\n<p>继承方式默认为 private</p>\n<p>派生类中有同名覆盖原则\nEmployee::Print()\n标明 调用基类的print函数,否则同名覆盖</p>\n<p>在派生类中,可以使用using 基类::成员, 将其公有化</p>\n<p>构造函数 用参数初始化表对数据尘缘初始化\nBox(int h,int w,int len):height(h),width(w),length(len) {}</p>\n<p>通过派生类的构造函数采用初始化参数表来调用基类的构造函数,对基类数据成员初始化\n志向数虚, 先调用 基类\n在什邡市,先执行派生类的析构函数,,然后再执行基类的析构函数</p>\n<p>派生类可以不写寄来额构造函数 前提是 基类没有定义任何构造函数 或者只定义了无参构造函数</p>\n<p>多重继承\nclass D:public A,private B,protected Complex{类D新增加的成员};</p>\n<p>多重继承派生类构造函数的执行顺序:先调用各基类的构造函数,再执行\n派生类构造函数,调用各基类构造函数的书序是按照声明派生类是基类出现的顺序</p>\n<p>多重继承引起的二义性问题\n对象.类名::成员 在类内访问用 类名::成员</p>\n<p>虚基类\n一个派生类有多个直接基类 而这些直接基类又有一个共同的基类\nclass 派生类名: virtual 继承方式 基类名\n虚基类的成员在多重派生类中在内存只有一份拷贝\n在构造函数中\nD(int i): A(i),B(i),C(i) {} 其中 A为虚基类 也要写出来\n虚基类的构造函数的执行顺序\nClass A;\nClass B;\nClass C:public A, virtual B {};\n调用顺序 B() A() C()\n虚基类的构造函数再非续集来之前调用\n同一层包含多个虚基类 则按声明书序调用\n弱虚基类由非虚基类派生而来,先要调用更高级的基类构造函数</p>\n<p>类的组合,一个类的对象作为一个咧的数据成员</p>\n<p>基类调用构造函数,内嵌对像调用构造函数,派生类调用构造函数</p>\n<p>派生类构造函数(总参数列表):基类构造函数名(参数表列),子对象名(参数表列) {}\n注意子对象名是在基类之后</p>\n<p>基类对象 = 派生列对象\n基类引用 = 派生类对象 此时不是别名,只是派生类中一部分的别名\n基类指针 = &派生类对象</p>\n<p>多态\n重载多态\n强制多态 类型转换\n包含多态 通过虚函数实现\n参数多态\n静态多态性 编译时多态性\n动态多态性 运行时多态性 通过 virtual functiion 实现</p>\n<p>虚函数\nclass Circle\n{\nvirtual float area() const;\n};</p>\n<p>使用基类指针访问基类和 派生列对象时, 根据指针指向的内存对象的实际类型调用相应\n也就是说虚函数 要 调用 所指向的那个类的同名函数 ,而不局限于指针的类</p>\n<p>虚函数只能是成员函数</p>\n<p>动态binding是C++的关键</p>\n<p>一般情况下,最好将基类析构函数生命为虚函数[ 关键]</p>\n<p>纯虚函数 在积累中声明时 值申明一个函数,没有函数体.\n在声明时 被 初始化 为0 的函数,\n格式: virtual 函数类型 函数名 (参数列表) = 0;</p>\n<p>抽象类 即 包含纯虚函数的类\n因为出心虚函数是不能调用 所以包含 纯虚函数 的 类是 无法简历对象的</p>\n<p>C++经典虚函数例子</p>\n<pre><code class="lang-javascript">#include <iostream>\n\nusing std::cout;\nusing std::cin;\nusing std::endl;\n\n// 基类\nclass Fruit{\npublic:\nvirtual void print(){\ncout<< "Fruit" <<endl;\n}\n};\n\nclass Banana: public Fruit{ // 一定要共有继承\npublic:\nvoid print(){ // 此处可省略virtual关键字,但是函数原型要与Fruit中虚函数 void print(); 完全一致\ncout<< "Banana" <<endl;\n}\n};\n\nclass Apple: public Fruit{\npublic:\nvoid print(){\ncout<< "Apple" <<endl;\n}\n};\n\nclass Pear: public Fruit{\npublic:\nvoid print(){\ncout<< "Pear" <<endl;\n}\n};\n\nclass Peach: public Fruit{\npublic:\nvoid print(){\ncout<< "Peach" <<endl;\n}\n};\n\nint main(void)\n{\nBanana ban;\nApple ape;\nPear par;\nPeach pch;\nFruit *frt[] = {&ban, &ape, &par, &pch};\n\nfor(int i = 0; i < 4; i++)\nfrt[i]->print(); // 一个基类指针,分别调用不同的子类对象(动态多态)\n\nsystem("PAUSE");\nreturn 0;\n}\n</code></pre>\n<p>C++综合复习题目之一\n4\n(8) derived::fun\n(9) base::fun\n5\n(10) constructing A\n(11) constructing A\n(12) constructing B\n(13)constructing A\n6\n(14) 30\n(15) 3.14159\n7\n1 3\n2 6\n1 3\n8\nBase::x is 10\nDerived1::x is 8\nDerived2::X is 30\nBase::x is 8\n9\nx=7,y=9\nx=8,u=10\n10\n1 9\n9 1\n2.7 1.5\n四\n1\nfstream.h\nifstream\nofstream\nifile.get(ch)\nofile.put(ch)\n2\ncin>>s;\nout("D:\\file.txt");\n97=<s[i]<=122\nout.put(s[i])\nout.close()\n五\n1</p>\n<h1 id="include-iostream-">include<iostream></h1>\n<p>using namespace std;</p>\n<p>class Student\n{\nprivate:\nchar <em>name;\nint age;\npublic:\nvoid print()\n{\ncout << "age:" << age << endl;\ncout << "name:" << name << endl;\n}\nStudent(char</em> n, int a)\n{\nname = new char[strlen(n) + 1];\nstrcpy_s(name, strlen(n)+1, n);\nage = a;\n}\n~Student()\n{\ndelete[]name;\n}\n};\nclass Postgrad : public Student\n{\nprivate:\nint credit;\npublic:\nvoid print()\n{\nStudent::print();\ncout << "credit:" << credit << endl;\n}\nPostgrad(char* n, int a, int c) :Student(n, a)\n{\ncredit = c;\n}\n~Postgrad()\n{ }\n};</p>\n<p>void main()\n{\nPostgrad pg("ZhangSan", 24, 120);\npg.print();\n}\n2</p>\n<pre><code class="lang-javascript">#include<iostream>\nusing namespace std;\nclass Complex\n{\nprivate:\ndouble real;\ndouble imag;\npublic:\nComplex(double r,double im)\n{\nreal = r;\nimag = im;\n}\nComplex & operator++(int)\n{ real++; return *this }\nfriend ostream & operator << (ostream&, Complex& );\nfriend istream & operator >> (istream&, Complex&);\n}\n~Complex() { }\n};\n\nostream & operator << (ostream&out, Complex& c)\n{\nout<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;\nreturn out;\n}\n\nistream & operator >> (istream& in, Complex& c)\n{\nin>>c.real;\nin>>c.imag;\nreturn in;\n}\n</code></pre>\n<p>如果构造方式不加说明,默认的派生方式为private</p>\n<p>构造函数的3项工作:\n基类初始化\n成员对象初始化\n执行派生类构造函数体</p>\n<p>二义性解决方案:\n虚基类\n作用域分辨符</p>\n<p>派生类如何实现对基类私有成员的访问?\n通过基类的成员函数\n什么是类型兼容规则?\n类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。\n派生类的构造函数是怎样的执行顺序,析构函数的执行顺序是如何实现的?\n首先执行基类的构造函数,随后执行派生类的构造函数,\n当撤销派生类对象时,限执行派生类的析构函数,再执行基类的析构函数\n继承与组合之间的区别与联系是什么?\n继承是纵向(同一系族),组合是横向(不同系族)\n在构造函数执行时,都是先执行基类\\内嵌成员对象,再执行类\\派生类对象构造函数</p>\n<p>什么是虚基类?它有什么作用?含有虚基类的派生类的构造函数有什么要求,什么是最\n远派生类,建立一个含有虚基类的派生类的对象时,为什么由最远派生类的构造函数负责虚\n基类的初始化?\n提供virtual base class方法,\n使得在继承间接相同基类时只保留一份成员,即同名成员在内存中只有1份拷贝\n每个派生类的构造函数都要为虚基类构造函数提供实参\n在派生体系中派生到最下层的类\n因为虚基类无论被从多少路径派生多少次,\n其派生类对象中永远只有一个内嵌的虚基类对象,\n这是无法使用派生路径上的各个构造函数,\n只能由当前派生类的构造函数来负责初始化虚基类对象</p>\n<p>友元函数不能继承</p>\n<p>设置虚基类的目的 消除二义性</p>\n<p>派生来的构造参数,先是基类的,然后是自身成员的\nXB::XB(int a,int b):XA(a),y(b){ }</p>\n<h6 id="-">###有待商讨</h6>\n<p>前置自增 后返回值\nINT& operator++()\n{\n++(this->m_i);\nreturn <em>this;\n}\n后置自增 先返回值\nconst INT operator++(int)\n{\nINT temp = this->m_i;\n++(</em>this);\nreturn temp;\n}</p>\n<p>注意先调用虚基类构造参数,然后是非续集类,最后是内嵌成员\nalways 构造与析构相反 i mean order</p>\n<p>期末考试复习3:弱态与虚函数练习\n1A 2D 3C 4A 5D 6D\n纯虚函数可以在函数说明是定义,也可以在函数实现时定义\n虚函数不能使友元函数,但是可以在另一个类中生命为 友元函数\n派生类的虚函数与 基类中的虚函数具有相同的名称\n相同的参数个数以及相公的对应参数类型 且返回类型相同</p>\n<p>虚函数声明只能出现在类定义的函数 原型 生命中,而不能再成员函数的函数体实现的时候.</p>\n<p>e.g.\npublic class A\n{\nprivate:\nint d;\npublic:\nfriend B::Geta(A a);\n}</p>\n<p>public class B\n{\npublic:\nvirtual int Geta(A &a)\n{\nreturn a->d;\n}\n7D\n8A\n9A\n10A\n11A\n12D\n13D\n二\n1\nD::show() called.208\n2\nThe A version A\nThe A version 1\nThe A version A\nThe A version 3\n三\n6在C++中,为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数。因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数。</p>\n<p>现在的问题是,我们想把Base做出抽象类,不能直接构造对象,需要在其中定义一个纯虚函数。如果其中没有其他合适的函数,可以把析构函数定义为纯虚的,</p>\n<p>构造函数不能是虚函数。而且,在构造函数中调用虚函数,实际执行的是父类的对应函数,因为自己还没有构造好, 多态是被disable的。</p>\n<p>7\nvirtual void fun1(int i)\n{}</p>\n<p>8\n抽象类:\n抽象类\n抽象类的派生函数不一定要给出春旭函数\n抽象类(abstract class):凡是包含纯虚函数的类。因为纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象\n目的:不用来定义对象,只作为基类去建立派生类。用户在此基础上根据需要定义出功能各异的派生类,再用这些派生类去建立对象</p>\n<p>关于函数引用返回</p>\n<p>返回非引用值\n在函数返回的地方 会讲返回值复制给临时对象,且其返回值即可以试局部对象,也可以是表达式的结果</p>\n<p>返回引用\n当函数返回引用累心的时候,没有复制返回值,\n而是返回对象的引用(即队形本身)</p>\n<p>返回引用坐直:\n返回的实际上是 变量的内存地址\n可以读写改地址对应的内存区域的值, 即是 左值, 可以出现在复制语句的左边</p>\n<p>汉化返回引用是 可以利用去哪聚变量 作为函数的返回\n或者在函数的形参表中有引用活在这指针(作为函数返回)这两只有一个共同点\n就是返回指向完毕以后,变量已然存在</p>\n<p>引用返回,效率跟高</p>\n<p>函数返回的对象引用 必须在调用函数前就已经存在\n不允许返回局部变量</p>\n<p>当不希望返回的对象被修改的时候,可以添加const</p>\n<p>函数重载如果是 仅仅是返回值不同是无法区分的</p>\n<p>right const\n可以作为区分 重载的标志 但是left不行 ( 奇技淫巧) (可忽略)</p>\n<p>注意 返回引用左值的时候 要用引用传入全局变量,并且返回他\n而且 返回的 类型也要是引用, 总之 都是引用就对了</p>\n<p>注意参数从右向左传</p>\n<p>Point myp1(1,1),myp2(4,5);\nLine line(myp1,myp2);\nLine line2(line);</p>\n<p>Point构造函数被调用 1,1\nPoint构造函数被调用 4,5\nPoint复制构造函数被调用 4,5\nPoint复制构造函数被调用 1,1</p>\n<p>注意参数是从右向左传</p>\n<p>c语言中函数参数处理顺序-从右向左:\n 下面我们来看2个案例,分析下c语言中函数参数处理顺序。\n 第一个:</p>\n<pre><code class="lang-javascript"> #include "stdio.h"\n void fn(int a,int b,int c)\n {\n printf("%d,%d,%d", a, b, c);\n }\n void main()\n {\n int a = 3;\n fn(a++, a++, a++);\n }\n</code></pre>\n<p> 输出结果:\n 5,4,3</p>\n<p>printf的格式说明:</p>\n<p>%a 浮点数、十六进制数字和p-记数法(C99)\n%A 浮点数、十六进制数字和p-记法(C99)\n%c 一个字符(char)\n%C 一个ISO宽字符\n%d 有符号十进制整数(int)(%ld、%Ld:长整型数据(long),%hd:输出短整形。) \n%e 浮点数、e-记数法\n%E 浮点数、E-记数法\n%f 单精度浮点数(默认float)、十进制记数法(%.nf 这里n表示精确到小数位后n位.十进制计数)\n%g 根据数值不同自动选择%f或%e.\n%G 根据数值不同自动选择%f或%e.\n%i 有符号十进制数(与%d相同)\n%o 无符号八进制整数\n%p 指针\n%s 对应字符串char<em>(%s == %hs == %hS 输出 窄字符)\n%S 对应宽字符串WCAHR</em>(%ws == %S 输出宽字符串)\n%u 无符号十进制整数(unsigned int)\n%x 使用十六进制数字0f的无符号十六进制整数 \n%X 使用十六进制数字0f的无符号十六进制整数\n%% 打印一个百分号\n%I64d\n用于INT64 或者 long long\n%I64u\n用于UINT64 或者 unsigned long long\n%I64x\n用于64位16进制数据</p>\n<p>%m.ne和%-m.ne:m、n和”-”字符含义与前相同。此处n指数据的数字部分的小数位数,m表示整个输出数据所占的宽度。</p>\n<p>float类型的字面常量,后面需要加上f或者F来表示是一个单精度浮点数。只所以要这样写,是因为默认的浮点数常量都是double类型。</p>\n<p>oct为八进制,hex为十六进制,dec为十进制。</p>\n<p>setw(int n)\n如果数据的实际宽度小于指定宽度,按右对齐的方式在左边留空;如果数据的实际宽度大于指定宽度,则按实际宽度输出,即指定宽度失效。</p>\n<p>cin.getline(s1,N,结束符); //默认结束符为 \\n\ncin.get(s2,N,结束符); //可以包括空格</p>\n<p>ostringstream输出字符串流(向字符串输出)\ncerr标准错误输出 , 无缓冲, 立即输出\nclog标准错误输出, 有缓冲, 缓冲区 满时 再输出</p>\n<p>ofstream("filename", iosmode);\n或者\nofstream of;\nof.open("filename", iosmode);\n以上两种都是静态对像</p>\n<p>动态对象\nofstream <em>ofp = new ofstream;\nofg->open("filename",iosmode);\n构造动态对象的同事同时打开文件\nofstream </em>ofp = new ofstream("filename", iosmode);</p>\n<p>iosmode:\n以下是 #include<fstream.h>版本\nios:app 文件尾添加\nios::ate 打开显存文件并移到文件尾\nios::in 打开一个输入文件(保护文件)\nios::out 输出方式打开,隐含模式\nios::trunc 打开文件,抹去原有内容\nios::binary 二进制方式打开,默认是文本方式\nIos::nocreate 打开已有文件,否则失败\nios::noreplace 文件不存在则生成,否则失败\n重要\n若果是</p>\n<pre><code class="lang-javascript"> #include<fstream>\nusing namespace std;版本的话\n上面的ios全部变成ios_base\n\n\ncout.put('A'); //等价于 cout<<'A';\n\nof.put('A'); //等价于 of<<'A';\n\nofstream tfile("data.dat",ios_base::binary);\ntfile.write((char*)&dt,sizeof(dt));\ntfile.close();\n需要注意的是 要有(char*)& 这是固定的格式\n\nDate dt = (5,8,2017};\nofstream tflie("data.dat");\ntflie<<dt.m<<','<<dt.d<<','<<dy.y<<endl;\ntfile.close();\n</code></pre>\n<p>tellp() 返回当前文件指针位置, 便于简历索引\nseekp( n ,pos) 设置指针位置, 便于快速定位随机读写\npos:\nios_base::beg 从文件头开始\nios_base::end 从文件尾开始\nios_base::cur 从文件指针的当前位置开始\nseekp(n)\n缺省值为 ios_base::beg</p>\n<p>flush\n与Cd fflush函数类似\n清空IO缓冲区到文件中, 防止出现同时读写同意文件时 内容不同步</p>\n<p>clear函数\n清楚(复位)所有错误标准机\n包括 goodbit, failbit, eofbit, badbit\n同一流对象在打开过一个文件并关闭后,再打开另一个文件前最好先调用一次clear函数\n给流对象复位</p>\n<p>eof() 错误处理函数 遇到文件尾则返回一个非0 值申明一个函数\nbad() fail() good()</p>\n<p>cout.width(10);\n是宽度为10</p>\n<p>setiosflags(ios_base::left) 左对齐\nsetiosflags(ios_base::right) 右对齐 默认方式</p>\n<p>setiosflags(ios_base::uppercase)\n京字母按大写方式输出十六进制</p>\n<p>dec 10\noct 8\nhex 16</p>\n<p>如果不设置 Ios_base::fixed 或者ios_base::scientific\n相当于 C中printf不指定 %f 或者 %e 则 自动用 %g格式输出, 始终按照6位输出</p>\n<p>ofstream outfile("payroll.dat",ios_base::binary);\noutfile.write((char*)&employee1, sizeof(employee1));\noutfile.close()\n如ifstream</p>\n<p>ifstream is("plauroll.bat",ios_base::binary);\nif(is.good())\n{\nis.read((char*)&employee1,sizeof(employee1));\ncout<<employee1.name<<' '<<employee1.salary<<endl;\n}\nelse cout<<"ERROR:Cannot open file: playroo.dat"<<endl;\nis.close();\n}</p>\n<h1 id="include-iostream-">include<iostream></h1>\n<h1 id="include-fstream-">include<fstream></h1>\n<p>using namespace std;\nvoid main()\n{\nchar ch;\nifstream tfile("playroll.dat",ios_base::binary);\nif(tfile.good())\n{\ntfile.seekp(sizeof(double),ios_base::beg);\nwhile(tfile.good())\n{\ntfile.get(ch);\nif(!ch) break;\ncout<<ch;\n}\n}\nelse cout<<"ERROR: Cannot open file: playroll.dat"<<endl;\ntfile.close();\n}</p>\n<p>ignore(n,终止字符)\n跳过输入流中你的n个字符,或者 知道指定的终止字符(终止字符也跳过)\n终止字符可以使任意字符,但通常是'n</p>\n<p>注意逗号表达式是最后一个表达式的结果</p>\n<p>sync() 清空输入胡输出缓冲区, 把输入丢掉 把输出打印出来 (或送到文件中)]</p>\n<p>cin.clear() ; //清楚std::cin的错误状态\ncin.sync(); //清空输入缓冲区\n这两个函数要一起使用</p>\n', 'class 类名\n{\nprivate:\n私有成员数据;\nprotected:\n保护成员;\npublic:\n公用数据和函数;\n};\n\n::作用域限定符\n\ninline函数 内联函数\n在函数首行左端加inline\n如果在类体中定义的成员函数中没有循环控制结构,\n编译系统会自动视为inline函数\n类内申明内置成员函数,可以省去inline,类外不能省去\n\n类的属性:封装性\n\n用类定义对象时,系统会为每一个对象分配存储空间\n每个对象所占用的存储空间只是对象的数据成员所占用的空间\n不包括函数代码\n\n引用对象的3中方法\n1通过对象名和成员运算符访问对象中的成员 对象名.成员\n2通过指向对象的指针访问对象中的成员 指针->成员\n3通过对象的引用变量访问对象中的成员 对象引用.成员\n\n构造函数:特殊的成员函数,专门用来处理对象的初始化,\n1不需要用户调用,自动执行\n2构造函数的名字与类名相同\n3没有函数类型 不返回任何值\n\n构造函数类型(必须是Public成员)\n默认构造函数(空构造函数)\n不带参数的构造函数\n带参数的构造函数\n函数体传递参数\n通过参数初始化来传递\n指定默认参数\n\n构造函数重载 参数类型或者个数不同\n\n析构函数 ~类名\n\n先构造的后析构\n\n对象赋值的一般形式:对象名1=对象名2\n对象的拷贝 类名 对象2(对象1) 或者 类名 对象名2 = 对象名1\ne.g. Box box2(box1);\n调用拷贝构造函数\nBox::Box(const Box& b)\n{height = b.height;\nwidth = b.width;\nlength = b.length;}\n\n构造函数只有一个参数,参数是本类的对象\n\n对象的隐式复制:在对象作为函数参数或返回值时,会发生隐式复制。但都会调用拷贝构造函数\ntoday = func(today); 其中函数中的对象都是在函数所在这一句执行完之后释放\n\n浅拷贝:比如struct中有一个变量是地址,这儿时候用 b=a,此时b的那个变量地址\n和a中的相同 这就造成了地址的共享\n\n对象数组的初始化\n类名 对象名[长度] = { 构造函数(实参列表1),构造函数(实参列表2),...}\n\n对象指针,可是 用类来定义的 指针,也可以是 志向对象数据成员的指针变量。\n也可以是 指向 对象成员函数的指针\n形式 数据类型 (类名::*指针变量名)(参数列表);\ne.g. void (Time::*p2) ();\np3 = &Time::get_time;\n(t1.*p3)();\n\n每个成员函数都包含一个特殊的指针,即this 其值是当前被调用的成员函数所在的对象起始地址\n\n共用数据的保护\nconst int a =3;\n则a不能改变 const 比 #define 的好处是 const 有类型\nconst 数据类型名 变量名 = 初值表达式;\nconst 数据类型名 * 指针变量名; 指向的内存空间不能改变 自身指向地址可以更改\n数据类型名* const 指针变量名 = 处置表达式;\n自身内容 指向的地址不可更改的指针变量 常指针\n\n类名 const 对象名(参数列表);\n自身内容不可更改 不能调用非const成员函数\n\nconst 类名* 指针变量名;\n指向的空间不能更改 自身的指向可以更改\n\n类名 * const 指针变量名 = 初值表达式;\n指向的地址 不可更改的类指针\n\nconst 类名 & 对象名 = 初值表达式;\n常引用 其值为只读\n\nconst 数据类型名 变量名; 的初始化\n可以通过参数初始化表[注意是表]\n\n\n数据类型名 成员函数(参数列表) const;\n声明常成员函数,函数体不能更改类成员函数\n\n数据类型名 类名::成员函数名(参数列表) const\n{ ... }\n定义常成员函数 ,函数体不能更改 类成员变量\n\n\n数据成员 非const成员函数 const成员函数\n非const数据成员 可以引用 也可以改变值 可以引用 但不能改变值\nconst数据成员 可以一用 但不能改变值 可以引用 但不能改变值\nconst对象的数据成员 不允许引用和改变值 可以引用 但不可以改变值\n\n提高效率 用 引用来传递对象\n常成员函数 = 只读访问接口\n\n静态数据成员\nstatic int num;\n实现同类对象之间的数据共享\n\n初始化方式\nInt student::num = 0;\n或者声明一个不属于任何对象的 静态成员函数类专门负责静态常远的初始化\npublic: static void set_default(int d,int m, int y)\n{ default_day.d= d;\ndefault_day.m = m;\ndefault_day.y = y;}\n\n静态成员实际上是全局变量 在main()函数结束后才释放\n静态成员函数没有this指针\n\n运算符 重载\n函数类型 operator 运算符名称呢过(形参列表)\n{ 对运算符虫子啊处理的函数体}\n\nComplex operator+ (Complex& c1, Complex& c2);\n\n不能重载的运算符 . .* :: sizeof ?:\n\nComplex & operator + (Complex & c2);\nComplex & operator * (float c2);\nComplex & operator = (Complex & c2);\nComplex & operator > (Complex & c2);\n单目运算符\nComplex & operator ! ();\nComplex & operator + ();\nComplex & operator ++ ();\nComplex & operator () ();\n\n前置自增\nDate operator ++()\n后置自增\nDate &operator ++ (int)\n\n友元函数\nfriend void Print(const Date& D);\nfriend 函数类型 operator 运算符名称(参数列表);\n<< >> 不能够重载为成员函数 = [] () 不能重载为友元函数\n\n将其他类的尘缘函数声明为类的有缘\n如果一个类A 是类B 的 子类, 那么可以在A中声明一个B的函数为友元函数\nfriend Student::Print();\nfriend B::Print();\n\n将类声明为类的友元\n如\nclass Date\n{\nfriend Student;\n};\nclass Student\n{\nDate birthday;\npublic:\nvoid Print();\nvoid Copy();\n};\n这个时候 Student的成员函数可以访问birtday的私有成员\n\nfriend ostream& operator<< (ostream&,Complex&);\n在类外\nostream& operator<<(ostream& output, Complex& c)\n{output<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;\nreturn output;}\n\n转换构造函数\nComplex(double r) { real = r; imag = i; }\n\n派生的一般形式\nclass 派生类名:[继承方式] 基类名\n{ 新增加的成员 };\n\n继承性质 基类中丰源访问权限 派生类中成员的访问权限\nPublic Public Public\nprotected protected\nprivate 不可访问\n\nprotected Public protected\nprotected protected\nprivate 不可访问\n\nprivate public private\nprotected private\nprivate 不可访问\n\n继承方式默认为 private\n\n\n派生类中有同名覆盖原则\nEmployee::Print()\n标明 调用基类的print函数,否则同名覆盖\n\n在派生类中,可以使用using 基类::成员, 将其公有化\n\n构造函数 用参数初始化表对数据尘缘初始化\nBox(int h,int w,int len):height(h),width(w),length(len) {}\n\n通过派生类的构造函数采用初始化参数表来调用基类的构造函数,对基类数据成员初始化\n志向数虚, 先调用 基类\n在什邡市,先执行派生类的析构函数,,然后再执行基类的析构函数\n\n派生类可以不写寄来额构造函数 前提是 基类没有定义任何构造函数 或者只定义了无参构造函数\n\n多重继承\nclass D:public A,private B,protected Complex{类D新增加的成员};\n\n多重继承派生类构造函数的执行顺序:先调用各基类的构造函数,再执行\n派生类构造函数,调用各基类构造函数的书序是按照声明派生类是基类出现的顺序\n\n多重继承引起的二义性问题\n对象.类名::成员 在类内访问用 类名::成员\n\n虚基类\n一个派生类有多个直接基类 而这些直接基类又有一个共同的基类\nclass 派生类名: virtual 继承方式 基类名\n虚基类的成员在多重派生类中在内存只有一份拷贝\n在构造函数中\nD(int i): A(i),B(i),C(i) {} 其中 A为虚基类 也要写出来\n虚基类的构造函数的执行顺序\nClass A;\nClass B;\nClass C:public A, virtual B {};\n调用顺序 B() A() C()\n虚基类的构造函数再非续集来之前调用\n同一层包含多个虚基类 则按声明书序调用\n弱虚基类由非虚基类派生而来,先要调用更高级的基类构造函数\n\n类的组合,一个类的对象作为一个咧的数据成员\n\n基类调用构造函数,内嵌对像调用构造函数,派生类调用构造函数\n\n派生类构造函数(总参数列表):基类构造函数名(参数表列),子对象名(参数表列) {}\n注意子对象名是在基类之后\n\n基类对象 = 派生列对象\n基类引用 = 派生类对象 此时不是别名,只是派生类中一部分的别名\n基类指针 = &派生类对象\n\n多态\n重载多态\n强制多态 类型转换\n包含多态 通过虚函数实现\n参数多态\n静态多态性 编译时多态性\n动态多态性 运行时多态性 通过 virtual functiion 实现\n\n虚函数\nclass Circle\n{\nvirtual float area() const;\n};\n\n使用基类指针访问基类和 派生列对象时, 根据指针指向的内存对象的实际类型调用相应\n也就是说虚函数 要 调用 所指向的那个类的同名函数 ,而不局限于指针的类\n\n虚函数只能是成员函数\n\n动态binding是C++的关键\n\n一般情况下,最好将基类析构函数生命为虚函数[ 关键]\n\n纯虚函数 在积累中声明时 值申明一个函数,没有函数体.\n在声明时 被 初始化 为0 的函数,\n格式: virtual 函数类型 函数名 (参数列表) = 0;\n\n抽象类 即 包含纯虚函数的类\n因为出心虚函数是不能调用 所以包含 纯虚函数 的 类是 无法简历对象的\n\nC++经典虚函数例子\n\n\n```javascript\n#include <iostream>\n\nusing std::cout;\nusing std::cin;\nusing std::endl;\n\n// 基类\nclass Fruit{\npublic:\nvirtual void print(){\ncout<< "Fruit" <<endl;\n}\n};\n\nclass Banana: public Fruit{ // 一定要共有继承\npublic:\nvoid print(){ // 此处可省略virtual关键字,但是函数原型要与Fruit中虚函数 void print(); 完全一致\ncout<< "Banana" <<endl;\n}\n};\n\nclass Apple: public Fruit{\npublic:\nvoid print(){\ncout<< "Apple" <<endl;\n}\n};\n\nclass Pear: public Fruit{\npublic:\nvoid print(){\ncout<< "Pear" <<endl;\n}\n};\n\nclass Peach: public Fruit{\npublic:\nvoid print(){\ncout<< "Peach" <<endl;\n}\n};\n\nint main(void)\n{\nBanana ban;\nApple ape;\nPear par;\nPeach pch;\nFruit *frt[] = {&ban, &ape, &par, &pch};\n\nfor(int i = 0; i < 4; i++)\nfrt[i]->print(); // 一个基类指针,分别调用不同的子类对象(动态多态)\n\nsystem("PAUSE");\nreturn 0;\n}\n\n```\n\n\nC++综合复习题目之一\n4\n(8) derived::fun\n(9) base::fun\n5\n(10) constructing A\n(11) constructing A\n(12) constructing B\n(13)constructing A\n6\n(14) 30\n(15) 3.14159\n7\n1 3\n2 6\n1 3\n8\nBase::x is 10\nDerived1::x is 8\nDerived2::X is 30\nBase::x is 8\n9\nx=7,y=9\nx=8,u=10\n10\n1 9\n9 1\n2.7 1.5\n四\n1\nfstream.h\nifstream\nofstream\nifile.get(ch)\nofile.put(ch)\n2\ncin>>s;\nout("D:\\\\file.txt");\n97=<s[i]<=122\nout.put(s[i])\nout.close()\n五\n1\n#include<iostream>\nusing namespace std;\n\n\nclass Student\n{\nprivate:\nchar *name;\nint age;\npublic:\nvoid print()\n{\ncout << "age:" << age << endl;\ncout << "name:" << name << endl;\n}\nStudent(char* n, int a)\n{\nname = new char[strlen(n) + 1];\nstrcpy_s(name, strlen(n)+1, n);\nage = a;\n}\n~Student()\n{\ndelete[]name;\n}\n};\nclass Postgrad : public Student\n{\nprivate:\nint credit;\npublic:\nvoid print()\n{\nStudent::print();\ncout << "credit:" << credit << endl;\n}\nPostgrad(char* n, int a, int c) :Student(n, a)\n{\ncredit = c;\n}\n~Postgrad()\n{ }\n};\n\nvoid main()\n{\nPostgrad pg("ZhangSan", 24, 120);\npg.print();\n}\n2\n\n\n```javascript\n#include<iostream>\nusing namespace std;\nclass Complex\n{\nprivate:\ndouble real;\ndouble imag;\npublic:\nComplex(double r,double im)\n{\nreal = r;\nimag = im;\n}\nComplex & operator++(int)\n{ real++; return *this }\nfriend ostream & operator << (ostream&, Complex& );\nfriend istream & operator >> (istream&, Complex&);\n}\n~Complex() { }\n};\n\nostream & operator << (ostream&out, Complex& c)\n{\nout<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;\nreturn out;\n}\n\nistream & operator >> (istream& in, Complex& c)\n{\nin>>c.real;\nin>>c.imag;\nreturn in;\n}\n\n```\n如果构造方式不加说明,默认的派生方式为private\n\n构造函数的3项工作:\n基类初始化\n成员对象初始化\n执行派生类构造函数体\n\n二义性解决方案:\n虚基类\n作用域分辨符\n\n派生类如何实现对基类私有成员的访问?\n通过基类的成员函数\n什么是类型兼容规则?\n类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。\n派生类的构造函数是怎样的执行顺序,析构函数的执行顺序是如何实现的?\n首先执行基类的构造函数,随后执行派生类的构造函数,\n当撤销派生类对象时,限执行派生类的析构函数,再执行基类的析构函数\n继承与组合之间的区别与联系是什么?\n继承是纵向(同一系族),组合是横向(不同系族)\n在构造函数执行时,都是先执行基类\\内嵌成员对象,再执行类\\派生类对象构造函数\n\n什么是虚基类?它有什么作用?含有虚基类的派生类的构造函数有什么要求,什么是最\n远派生类,建立一个含有虚基类的派生类的对象时,为什么由最远派生类的构造函数负责虚\n基类的初始化?\n提供virtual base class方法,\n使得在继承间接相同基类时只保留一份成员,即同名成员在内存中只有1份拷贝\n每个派生类的构造函数都要为虚基类构造函数提供实参\n在派生体系中派生到最下层的类\n因为虚基类无论被从多少路径派生多少次,\n其派生类对象中永远只有一个内嵌的虚基类对象,\n这是无法使用派生路径上的各个构造函数,\n只能由当前派生类的构造函数来负责初始化虚基类对象\n\n友元函数不能继承\n\n设置虚基类的目的 消除二义性\n\n派生来的构造参数,先是基类的,然后是自身成员的\nXB::XB(int a,int b):XA(a),y(b){ }\n#########有待商讨\n\n\n前置自增 后返回值\nINT& operator++()\n{\n++(this->m_i);\nreturn *this;\n}\n后置自增 先返回值\nconst INT operator++(int)\n{\nINT temp = this->m_i;\n++(*this);\nreturn temp;\n}\n\n注意先调用虚基类构造参数,然后是非续集类,最后是内嵌成员\nalways 构造与析构相反 i mean order\n\n期末考试复习3:弱态与虚函数练习\n1A 2D 3C 4A 5D 6D\n纯虚函数可以在函数说明是定义,也可以在函数实现时定义\n虚函数不能使友元函数,但是可以在另一个类中生命为 友元函数\n派生类的虚函数与 基类中的虚函数具有相同的名称\n相同的参数个数以及相公的对应参数类型 且返回类型相同\n\n虚函数声明只能出现在类定义的函数 原型 生命中,而不能再成员函数的函数体实现的时候.\n\ne.g.\npublic class A\n{\nprivate:\nint d;\npublic:\nfriend B::Geta(A a);\n}\n\npublic class B\n{\npublic:\nvirtual int Geta(A &a)\n{\nreturn a->d;\n}\n7D\n8A\n9A\n10A\n11A\n12D\n13D\n二\n1\nD::show() called.208\n2\nThe A version A\nThe A version 1\nThe A version A\nThe A version 3\n三\n6在C++中,为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数。因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数。\n\n现在的问题是,我们想把Base做出抽象类,不能直接构造对象,需要在其中定义一个纯虚函数。如果其中没有其他合适的函数,可以把析构函数定义为纯虚的,\n\n构造函数不能是虚函数。而且,在构造函数中调用虚函数,实际执行的是父类的对应函数,因为自己还没有构造好, 多态是被disable的。\n\n7\nvirtual void fun1(int i)\n{}\n\n8\n抽象类:\n抽象类\n抽象类的派生函数不一定要给出春旭函数\n抽象类(abstract class):凡是包含纯虚函数的类。因为纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象\n目的:不用来定义对象,只作为基类去建立派生类。用户在此基础上根据需要定义出功能各异的派生类,再用这些派生类去建立对象\n\n关于函数引用返回\n\n返回非引用值\n在函数返回的地方 会讲返回值复制给临时对象,且其返回值即可以试局部对象,也可以是表达式的结果\n\n返回引用\n当函数返回引用累心的时候,没有复制返回值,\n而是返回对象的引用(即队形本身)\n\n返回引用坐直:\n返回的实际上是 变量的内存地址\n可以读写改地址对应的内存区域的值, 即是 左值, 可以出现在复制语句的左边\n\n汉化返回引用是 可以利用去哪聚变量 作为函数的返回\n或者在函数的形参表中有引用活在这指针(作为函数返回)这两只有一个共同点\n就是返回指向完毕以后,变量已然存在\n\n\n引用返回,效率跟高\n\n函数返回的对象引用 必须在调用函数前就已经存在\n不允许返回局部变量\n\n当不希望返回的对象被修改的时候,可以添加const\n\n函数重载如果是 仅仅是返回值不同是无法区分的\n\nright const\n可以作为区分 重载的标志 但是left不行 ( 奇技淫巧) (可忽略)\n\n注意 返回引用左值的时候 要用引用传入全局变量,并且返回他\n而且 返回的 类型也要是引用, 总之 都是引用就对了\n\n\n注意参数从右向左传\n\nPoint myp1(1,1),myp2(4,5);\nLine line(myp1,myp2);\nLine line2(line);\n\nPoint构造函数被调用 1,1\nPoint构造函数被调用 4,5\nPoint复制构造函数被调用 4,5\nPoint复制构造函数被调用 1,1\n\n注意参数是从右向左传\n\n\nc语言中函数参数处理顺序-从右向左:\n 下面我们来看2个案例,分析下c语言中函数参数处理顺序。\n 第一个:\n\n\n```javascript\n #include "stdio.h"\n void fn(int a,int b,int c)\n {\n printf("%d,%d,%d", a, b, c);\n }\n void main()\n {\n int a = 3;\n fn(a++, a++, a++);\n }\n```\n 输出结果:\n 5,4,3\n\n\nprintf的格式说明:\n\n%a 浮点数、十六进制数字和p-记数法(C99)\n%A 浮点数、十六进制数字和p-记法(C99)\n%c 一个字符(char)\n%C 一个ISO宽字符\n%d 有符号十进制整数(int)(%ld、%Ld:长整型数据(long),%hd:输出短整形。) \n%e 浮点数、e-记数法\n%E 浮点数、E-记数法\n%f 单精度浮点数(默认float)、十进制记数法(%.nf 这里n表示精确到小数位后n位.十进制计数)\n%g 根据数值不同自动选择%f或%e.\n%G 根据数值不同自动选择%f或%e.\n%i 有符号十进制数(与%d相同)\n%o 无符号八进制整数\n%p 指针\n%s 对应字符串char*(%s == %hs == %hS 输出 窄字符)\n%S 对应宽字符串WCAHR*(%ws == %S 输出宽字符串)\n%u 无符号十进制整数(unsigned int)\n%x 使用十六进制数字0f的无符号十六进制整数 \n%X 使用十六进制数字0f的无符号十六进制整数\n%% 打印一个百分号\n%I64d\n用于INT64 或者 long long\n%I64u\n用于UINT64 或者 unsigned long long\n%I64x\n用于64位16进制数据\n\n\n%m.ne和%-m.ne:m、n和”-”字符含义与前相同。此处n指数据的数字部分的小数位数,m表示整个输出数据所占的宽度。\n\nfloat类型的字面常量,后面需要加上f或者F来表示是一个单精度浮点数。只所以要这样写,是因为默认的浮点数常量都是double类型。\n\noct为八进制,hex为十六进制,dec为十进制。\n\nsetw(int n)\n如果数据的实际宽度小于指定宽度,按右对齐的方式在左边留空;如果数据的实际宽度大于指定宽度,则按实际宽度输出,即指定宽度失效。\n\ncin.getline(s1,N,结束符); //默认结束符为 \\n\ncin.get(s2,N,结束符); //可以包括空格\n\nostringstream输出字符串流(向字符串输出)\ncerr标准错误输出 , 无缓冲, 立即输出\nclog标准错误输出, 有缓冲, 缓冲区 满时 再输出\n\nofstream("filename", iosmode);\n或者\nofstream of;\nof.open("filename", iosmode);\n以上两种都是静态对像\n\n动态对象\nofstream *ofp = new ofstream;\nofg->open("filename",iosmode);\n构造动态对象的同事同时打开文件\nofstream *ofp = new ofstream("filename", iosmode);\n\niosmode:\n以下是 #include<fstream.h>版本\nios:app 文件尾添加\nios::ate 打开显存文件并移到文件尾\nios::in 打开一个输入文件(保护文件)\nios::out 输出方式打开,隐含模式\nios::trunc 打开文件,抹去原有内容\nios::binary 二进制方式打开,默认是文本方式\nIos::nocreate 打开已有文件,否则失败\nios::noreplace 文件不存在则生成,否则失败\n重要\n若果是\n\n\n```javascript\n #include<fstream>\nusing namespace std;版本的话\n上面的ios全部变成ios_base\n\n\ncout.put(\'A\'); //等价于 cout<<\'A\';\n\nof.put(\'A\'); //等价于 of<<\'A\';\n\nofstream tfile("data.dat",ios_base::binary);\ntfile.write((char*)&dt,sizeof(dt));\ntfile.close();\n需要注意的是 要有(char*)& 这是固定的格式\n\nDate dt = (5,8,2017};\nofstream tflie("data.dat");\ntflie<<dt.m<<\',\'<<dt.d<<\',\'<<dy.y<<endl;\ntfile.close();\n```\n\ntellp() 返回当前文件指针位置, 便于简历索引\nseekp( n ,pos) 设置指针位置, 便于快速定位随机读写\npos:\nios_base::beg 从文件头开始\nios_base::end 从文件尾开始\nios_base::cur 从文件指针的当前位置开始\nseekp(n)\n缺省值为 ios_base::beg\n\nflush\n与Cd fflush函数类似\n清空IO缓冲区到文件中, 防止出现同时读写同意文件时 内容不同步\n\nclear函数\n清楚(复位)所有错误标准机\n包括 goodbit, failbit, eofbit, badbit\n同一流对象在打开过一个文件并关闭后,再打开另一个文件前最好先调用一次clear函数\n给流对象复位\n\neof() 错误处理函数 遇到文件尾则返回一个非0 值申明一个函数\nbad() fail() good()\n\ncout.width(10);\n是宽度为10\n\nsetiosflags(ios_base::left) 左对齐\nsetiosflags(ios_base::right) 右对齐 默认方式\n\nsetiosflags(ios_base::uppercase)\n京字母按大写方式输出十六进制\n\ndec 10\noct 8\nhex 16\n\n如果不设置 Ios_base::fixed 或者ios_base::scientific\n相当于 C中printf不指定 %f 或者 %e 则 自动用 %g格式输出, 始终按照6位输出\n\nofstream outfile("payroll.dat",ios_base::binary);\noutfile.write((char*)&employee1, sizeof(employee1));\noutfile.close()\n如ifstream\n\n\nifstream is("plauroll.bat",ios_base::binary);\nif(is.good())\n{\nis.read((char*)&employee1,sizeof(employee1));\ncout<<employee1.name<<\' \'<<employee1.salary<<endl;\n}\nelse cout<<"ERROR:Cannot open file: playroo.dat"<<endl;\nis.close();\n}\n\n#include<iostream>\n#include<fstream>\nusing namespace std;\nvoid main()\n{\nchar ch;\nifstream tfile("playroll.dat",ios_base::binary);\nif(tfile.good())\n{\ntfile.seekp(sizeof(double),ios_base::beg);\nwhile(tfile.good())\n{\ntfile.get(ch);\nif(!ch) break;\ncout<<ch;\n}\n}\nelse cout<<"ERROR: Cannot open file: playroll.dat"<<endl;\ntfile.close();\n}\n\nignore(n,终止字符)\n跳过输入流中你的n个字符,或者 知道指定的终止字符(终止字符也跳过)\n终止字符可以使任意字符,但通常是\'n\n\n注意逗号表达式是最后一个表达式的结果\n\nsync() 清空输入胡输出缓冲区, 把输入丢掉 把输出打印出来 (或送到文件中)]\n\ncin.clear() ; //清楚std::cin的错误状态\ncin.sync(); //清空输入缓冲区\n这两个函数要一起使用', NULL, NULL, '2020-06-08 13:50:48', 1, 2),
('3f234fc148444c4ca36d23f19ed5bcbf', 1000002, 'C++对C的扩展', 'C++ C 扩展', '<p>2.与C语言的关系\n1.C语言是在实践的过程中逐步完善起来的</p>\n<p>没有深思熟虑的设计过程\n使用时存在很多“灰色地带”\n残留过多低级语言的特征\n直接利用指针进行内存操作\n2.C语言的目标是高效\n最终程序执行效率的高效</p>\n<p>3.当面向过程方法论暴露越来越多的缺陷的时候,业界开始考虑在工程项目中引入面向对象的设计方法,而第一个需要解决的问题就是:高效的面向对象语言,并且能够兼容已经存在的代码。\nC语言 + 面向对象方法论===》Objective C /C++</p>\n<p>4.C语言和C++并不是对立的竞争关系</p>\n<p>C++是C语言的加强,是一种更好的C语言\nC++是以C语言为基础的,并且完全兼容C语言的特性\n5.学习C++并不会影响原有的C语言知识,相反会加深对C的认知,学习C++可以接触到更多的软件设计方法,并带来更多的机会。</p>\n<p>C++是一种更强大的C,通过学习C++能够掌握更多的软件设计方法\nC++是Java/C#/D等现代开发语言的基础,学习C++后能够快速掌握这些语言\nC++是各大知名软件企业挑选人才的标准之一\n3.发展历史\n1.面向过程的结构化程序设计方法</p>\n<p>设计思路\n自顶向下、逐步求精。采用模块分解与功能抽象,自顶向下、分而治之。\n程序结构:\n按功能划分为若干个基本模块,形成一个树状结构。\n各模块间的关系尽可能简单,功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成。\n其模块化实现的具体方法是使用子程序。\n优点:\n有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。\n缺点:可重用性差、数据安全性差、难以开发大型软件和图形界面的应用软件\n把数据和处理数据的过程分离为相互独立的实体。\n当数据结构改变时,所有相关的处理过程都要进行相应的修改。\n每一种相对于老问题的新方法都要带来额外的开销。\n图形用户界面的应用程序,很难用过程来描述和实现,开发和维护也都很困难。\n2.面向对象的方法</p>\n<p>将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体——对象。\n对同类型对象抽象出其共性,形成类。\n类通过一个简单的外部接口,与外界发生关系。\n对象与对象之间通过消息进行通信。\n3.面向对象的基本概念</p>\n<p>对象\n一般意义上的对象:\n是现实世界中一个实际存在的事物。\n可以是有形的(比如一辆汽车),也可以是无形的(比如一项计划)。\n是构成世界的一个独立单位,具有\n静态特征:可以用某种数据来描述\n动态特征:对象所表现的行为或具有的功能\n面向对象方法中的对象:\n是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。\n属性:用来描述对象静态特征的数据项。\n行为:用来描述对象动态特征的操作序列。\n类\n分类——人类通常的思维方法\n分类所依据的原则——抽象\n忽略事物的非本质特征,只注意那些与当前目标有关的本质特征,从而找出事物的共性,把具有共同性质的事物划分为一类,得出一个抽象的概念。\n例如,石头、树木、汽车、房屋等都是人们在长期的生产和生活实践中抽象出的概念。\n面向对象方法中的”类”\n具有相同属性和服务的一组对象的集合\n为属于该类的全部对象提供了抽象的描述,包括属性和行为两个主要部分。\n类与对象的关系:\n犹如模具与铸件之间的关系,一个属于某类的对象称为该类的一个实例。\n封装\n也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。\n把对象的属性和服务结合成一个独立的系统单元。\n尽可能隐蔽对象的内部细节。对外形成一个边界(或者说一道屏障),只保留有限的对外接口使之与外部发生联系。\n继承对于软件复用有着重要意义,是面向对象技术能够提高软件开发效率的重要原因之一。\n定义:特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。\n例如:将轮船作为一个一般类,客轮便是一个特殊类。\n多态\n多态是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义。</p>\n<p>面向对象的软件工程\n面向对象的软件工程是面向对象方法在软件工程领域的全面应用。它包括:</p>\n<p>面向对象的分析(OOA)\n面向对象的设计(OOD)\n面向对象的编程(OOP)\n面向对象的测试(OOT)\n面向对象的软件维护(OOSM\n————————————————\n版权声明:本文为CSDN博主「小帅比simon」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。\n原文链接:<a href="https://blog.csdn.net/lzjsqn/java/article/details/72677499">https://blog.csdn.net/lzjsqn/java/article/details/72677499</a></p>\n', '2.与C语言的关系\n1.C语言是在实践的过程中逐步完善起来的\n\n没有深思熟虑的设计过程\n使用时存在很多“灰色地带”\n残留过多低级语言的特征\n直接利用指针进行内存操作\n2.C语言的目标是高效\n最终程序执行效率的高效\n\n3.当面向过程方法论暴露越来越多的缺陷的时候,业界开始考虑在工程项目中引入面向对象的设计方法,而第一个需要解决的问题就是:高效的面向对象语言,并且能够兼容已经存在的代码。\nC语言 + 面向对象方法论===》Objective C /C++\n\n4.C语言和C++并不是对立的竞争关系\n\nC++是C语言的加强,是一种更好的C语言\nC++是以C语言为基础的,并且完全兼容C语言的特性\n5.学习C++并不会影响原有的C语言知识,相反会加深对C的认知,学习C++可以接触到更多的软件设计方法,并带来更多的机会。\n\nC++是一种更强大的C,通过学习C++能够掌握更多的软件设计方法\nC++是Java/C#/D等现代开发语言的基础,学习C++后能够快速掌握这些语言\nC++是各大知名软件企业挑选人才的标准之一\n3.发展历史\n1.面向过程的结构化程序设计方法\n\n设计思路\n自顶向下、逐步求精。采用模块分解与功能抽象,自顶向下、分而治之。\n程序结构:\n按功能划分为若干个基本模块,形成一个树状结构。\n各模块间的关系尽可能简单,功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成。\n其模块化实现的具体方法是使用子程序。\n优点:\n有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。\n缺点:可重用性差、数据安全性差、难以开发大型软件和图形界面的应用软件\n把数据和处理数据的过程分离为相互独立的实体。\n当数据结构改变时,所有相关的处理过程都要进行相应的修改。\n每一种相对于老问题的新方法都要带来额外的开销。\n图形用户界面的应用程序,很难用过程来描述和实现,开发和维护也都很困难。\n2.面向对象的方法\n\n将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体——对象。\n对同类型对象抽象出其共性,形成类。\n类通过一个简单的外部接口,与外界发生关系。\n对象与对象之间通过消息进行通信。\n3.面向对象的基本概念\n\n对象\n一般意义上的对象:\n是现实世界中一个实际存在的事物。\n可以是有形的(比如一辆汽车),也可以是无形的(比如一项计划)。\n是构成世界的一个独立单位,具有\n静态特征:可以用某种数据来描述\n动态特征:对象所表现的行为或具有的功能\n面向对象方法中的对象:\n是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。\n属性:用来描述对象静态特征的数据项。\n行为:用来描述对象动态特征的操作序列。\n类\n分类——人类通常的思维方法\n分类所依据的原则——抽象\n忽略事物的非本质特征,只注意那些与当前目标有关的本质特征,从而找出事物的共性,把具有共同性质的事物划分为一类,得出一个抽象的概念。\n例如,石头、树木、汽车、房屋等都是人们在长期的生产和生活实践中抽象出的概念。\n面向对象方法中的”类”\n具有相同属性和服务的一组对象的集合\n为属于该类的全部对象提供了抽象的描述,包括属性和行为两个主要部分。\n类与对象的关系:\n犹如模具与铸件之间的关系,一个属于某类的对象称为该类的一个实例。\n封装\n也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。\n把对象的属性和服务结合成一个独立的系统单元。\n尽可能隐蔽对象的内部细节。对外形成一个边界(或者说一道屏障),只保留有限的对外接口使之与外部发生联系。\n继承对于软件复用有着重要意义,是面向对象技术能够提高软件开发效率的重要原因之一。\n定义:特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。\n例如:将轮船作为一个一般类,客轮便是一个特殊类。\n多态\n多态是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义。\n\n面向对象的软件工程\n面向对象的软件工程是面向对象方法在软件工程领域的全面应用。它包括:\n\n面向对象的分析(OOA)\n面向对象的设计(OOD)\n面向对象的编程(OOP)\n面向对象的测试(OOT)\n面向对象的软件维护(OOSM\n————————————————\n版权声明:本文为CSDN博主「小帅比simon」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。\n原文链接:https://blog.csdn.net/lzjsqn/java/article/details/72677499', '3f234fc148444c4ca36d23f19ed5bcbf', '3f234fc148444c4ca36d23f19ed5bcbf.jpg', '2020-06-08 13:52:59', 0, 1),
('4665714aff6d441397c2f852f2eadef5', 1000000, 'C++入门视频学习七集', 'C++ 入门 学习', '<h2 id="-">视频列表</h2>\n<p><strong>P0 标题 C++环境安装</strong></p>\n<p><strong>P1 标题 C++关键字</strong></p>\n<p><strong>P2 标题 C++常量</strong></p>\n<p><strong>P3 标题 C++对象</strong></p>\n<p><strong>P4 标题 C++指针</strong></p>\n<p><strong>P5 标题 C++条件语句</strong></p>\n<p><strong>P6 标题 C++循环语句</strong></p>\n', '##视频列表\n\n**P0 标题 C++环境安装**\n\n**P1 标题 C++关键字**\n\n**P2 标题 C++常量**\n\n**P3 标题 C++对象**\n\n**P4 标题 C++指针**\n\n**P5 标题 C++条件语句**\n\n**P6 标题 C++循环语句**', '4665714aff6d441397c2f852f2eadef5', '4665714aff6d441397c2f852f2eadef5.jpg', '2020-06-06 18:00:08', 2, 1),
('47d147c4497c4d21b9fd137370412e1e', 1000000, '反转链表', '反转链表 算法', '<p>定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。</p>\n<p>示例:</p>\n<p>输入: 1->2->3->4->5->NULL\n输出: 5->4->3->2->1->NULL</p>\n<p>限制:</p>\n<p>0 <= 节点个数 <= 5000</p>\n<pre><code class="lang-javascript">class Solution {\npublic:\n ListNode* reverseList(ListNode* head) {\n ListNode* cur = NULL, *pre = head;\n while (pre != NULL) {\n ListNode* t = pre->next;\n pre->next = cur;\n cur = pre;\n pre = t;\n }\n return cur;\n }\n};\n</code></pre>\n', '定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。\n\n示例:\n\n输入: 1->2->3->4->5->NULL\n输出: 5->4->3->2->1->NULL\n \n\n限制:\n\n0 <= 节点个数 <= 5000\n\n\n\n\n```javascript\nclass Solution {\npublic:\n ListNode* reverseList(ListNode* head) {\n ListNode* cur = NULL, *pre = head;\n while (pre != NULL) {\n ListNode* t = pre->next;\n pre->next = cur;\n cur = pre;\n pre = t;\n }\n return cur;\n }\n};\n\n```', NULL, NULL, '2020-06-08 14:54:42', 0, 2),
('48aadcaa5ed84ab7880be87ec5b4dd77', 1000000, 'Markdown编辑器使用方法', 'Markdown 编辑 使用 Mdito', '<h2 id="-mditor">欢迎使用Mditor</h2>\n<p><strong>Mditor是一款轻量级的markdown编辑器。取名自markdown + editor,用于实现页面markdown输入框的便利操作。</strong></p>\n<h2 id="markdown-">Markdown是什么</h2>\n<blockquote>\n<p>Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— <a href="https://zh.wikipedia.org/wiki/Markdown">维基百科</a></p>\n</blockquote>\n<h3 id="-">快捷键</h3>\n<p><strong>撤销 </strong><code>Ctrl + Z</code></p>\n<p><strong>恢复</strong><code>Ctrl + Y</code></p>\n<p><strong>加粗</strong><code>Ctrl + B</code></p>\n<p><strong>斜体</strong><code>Ctrl + I</code></p>\n<p><strong>链接</strong><code>Ctrl + L</code></p>\n<p><strong>图片</strong><code>Ctrl + G</code></p>\n<p><strong>代码</strong><code>Ctrl + Shift + K</code></p>\n<p><strong>代码块</strong><code>Ctrl + K</code></p>\n<h3 id="-">演示</h3>\n<hr>\n<p>[TOC]</p>\n<p>正如您在阅读的这份文档,它使用简单的符号标识不同的标题,将某些文字标记为<strong>粗体</strong>或者<em>斜体</em>,下面列举了几个高级功能,更多语法请查看帮助。 </p>\n<h3 id="-">代码块</h3>\n<pre><code class="lang-python">@requires_authorization\ndef somefunc(param1='', param2=0):\n '''A docstring'''\n if param1 > param2: # interesting\n print 'Greater'\n return (param2 - param1 + 1) or None\nclass SomeClass:\n pass\n>>> message = '''interpreter\n... prompt'''\n</code></pre>\n<h3 id="-">表格</h3>\n<pre><code class="lang-javascript">| Item | Value | Qty |\n| :-------- | --------:| :--: |\n| Computer | 1600 USD | 5 |\n| Phone | 12 USD | 12 |\n| Pipe | 1 USD | 234 |\n</code></pre>\n<h3 id="-">表格</h3>\n<table>\n<thead>\n<tr>\n<th style="text-align:left">Item</th>\n<th style="text-align:right">Value</th>\n<th style="text-align:center">Qty</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align:left">Computer</td>\n<td style="text-align:right">1600 USD</td>\n<td style="text-align:center">5</td>\n</tr>\n<tr>\n<td style="text-align:left">Phone</td>\n<td style="text-align:right">12 USD</td>\n<td style="text-align:center">12</td>\n</tr>\n<tr>\n<td style="text-align:left">Pipe</td>\n<td style="text-align:right">1 USD</td>\n<td style="text-align:center">234</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<p>感谢阅读这份帮助文档。开启全新的记录与分享体验吧。</p>\n', '##欢迎使用Mditor\n\n**Mditor是一款轻量级的markdown编辑器。取名自markdown + editor,用于实现页面markdown输入框的便利操作。**\n\n##Markdown是什么\n> Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [维基百科](https://zh.wikipedia.org/wiki/Markdown)\n\n###快捷键\n\n**撤销 **`Ctrl + Z`\n\n**恢复**`Ctrl + Y`\n\n**加粗**`Ctrl + B`\n\n**斜体**`Ctrl + I`\n\n**链接**`Ctrl + L`\n\n**图片**`Ctrl + G`\n\n**代码**`Ctrl + Shift + K`\n\n**代码块**`Ctrl + K`\n\n###演示\n\n-------------------\n\n[TOC]\n\n\n正如您在阅读的这份文档,它使用简单的符号标识不同的标题,将某些文字标记为**粗体**或者*斜体*,下面列举了几个高级功能,更多语法请查看帮助。 \n\n### 代码块\n``` python\n@requires_authorization\ndef somefunc(param1=\'\', param2=0):\n \'\'\'A docstring\'\'\'\n if param1 > param2: # interesting\n print \'Greater\'\n return (param2 - param1 + 1) or None\nclass SomeClass:\n pass\n>>> message = \'\'\'interpreter\n... prompt\'\'\'\n```\n\n### 表格\n\n\n```javascript\n| Item | Value | Qty |\n| :-------- | --------:| :--: |\n| Computer | 1600 USD | 5 |\n| Phone | 12 USD | 12 |\n| Pipe | 1 USD | 234 |\n\n```\n\n### 表格\n| Item | Value | Qty |\n| :-------- | --------:| :--: |\n| Computer | 1600 USD | 5 |\n| Phone | 12 USD | 12 |\n| Pipe | 1 USD | 234 |\n\n\n---------\n感谢阅读这份帮助文档。开启全新的记录与分享体验吧。\n\n\n', NULL, NULL, '2020-06-03 09:37:43', 18, 2),
('48c85c7987b743b8adeee7a1158fc89f', 1000002, '对称的二叉树', '二叉树 面试题 ', '<p>方法一: 递归法</p>\n<pre><code class="lang-javascript">class Solution {\npublic:\n bool isSymmetric(TreeNode* root) {\n bool res = true;\n if (root!=NULL)\n {\n res = helper(root->left,root->right);\n }\n return res;\n }\n\n bool helper(TreeNode*A, TreeNode* B)\n {\n // 先写递归终止条件\n if (A==NULL && B==NULL)\n return true;\n // 如果其中之一为空,也不是对称的\n if (A==NULL || B==NULL)\n return false;\n // 走到这里二者一定不为空\n if (A->val != B->val)\n return false;\n // 前序遍历\n return helper(A->left,B->right) && helper(A->right,B->left);\n }\n};\n</code></pre>\n<p>方法二: 迭代法</p>\n<pre><code class="lang-javascript">class Solution {\npublic:\n bool isSymmetric(TreeNode* root) {\n if (root ==NULL)\n return true;\n //用队列保存节点\n queue<TreeNode*> q;\n //将根节点的左右孩子放到队列中\n q.push(root->left);\n q.push(root->right);\n while(!q.empty())\n {\n //从队列中取出两个节点,再比较这两个节点\n TreeNode* A = q.front();\n q.pop();\n TreeNode* B = q.front();\n q.pop();\n //如果两个节点都为空就继续循环,两者有一个为空就返回false\n if (A==NULL && B==NULL)\n continue;\n if (A==NULL || B==NULL)\n return false;\n if (A->val != B->val)\n return false;\n //将左子树的左孩子, 右子树的右孩子放入队列\n q.push(A->left);\n q.push(B->right);\n //将左子树的右孩子,右子树的左孩子放入队列\n q.push(A->right);\n q.push(B->left);\n }\n return true;\n }\n};\n</code></pre>\n', '方法一: 递归法\n\n```javascript\nclass Solution {\npublic:\n bool isSymmetric(TreeNode* root) {\n bool res = true;\n if (root!=NULL)\n {\n res = helper(root->left,root->right);\n }\n return res;\n }\n\n bool helper(TreeNode*A, TreeNode* B)\n {\n // 先写递归终止条件\n if (A==NULL && B==NULL)\n return true;\n // 如果其中之一为空,也不是对称的\n if (A==NULL || B==NULL)\n return false;\n // 走到这里二者一定不为空\n if (A->val != B->val)\n return false;\n // 前序遍历\n return helper(A->left,B->right) && helper(A->right,B->left);\n }\n};\n```\n方法二: 迭代法\n\n```javascript\nclass Solution {\npublic:\n bool isSymmetric(TreeNode* root) {\n if (root ==NULL)\n return true;\n //用队列保存节点\n queue<TreeNode*> q;\n //将根节点的左右孩子放到队列中\n q.push(root->left);\n q.push(root->right);\n while(!q.empty())\n {\n //从队列中取出两个节点,再比较这两个节点\n TreeNode* A = q.front();\n q.pop();\n TreeNode* B = q.front();\n q.pop();\n //如果两个节点都为空就继续循环,两者有一个为空就返回false\n if (A==NULL && B==NULL)\n continue;\n if (A==NULL || B==NULL)\n return false;\n if (A->val != B->val)\n return false;\n //将左子树的左孩子, 右子树的右孩子放入队列\n q.push(A->left);\n q.push(B->right);\n //将左子树的右孩子,右子树的左孩子放入队列\n q.push(A->right);\n q.push(B->left);\n }\n return true;\n }\n};\n\n```\n', NULL, NULL, '2020-06-08 14:52:00', 1, 2),
('4e3cb62d2aa7406e9b2b44da552968cb', 1000000, 'MySQL数据库8.0.20.0安装包', 'MySQL 数据库 安装包', '<h2 id="mysql-">MySQL数据库</h2>\n<p>MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。</p>\n<p>MySQL 是开源的,所以你不需要支付额外的费用。</p>\n<p>MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。</p>\n<p>MySQL 使用标准的 SQL 数据语言形式。</p>\n<p>MySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。</p>\n<p>MySQL 对PHP有很好的支持,PHP 是目前最流行的 Web 开发语言。</p>\n<p>MySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。</p>\n<p>MySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。</p>\n', '##MySQL数据库\n\nMySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。\n\nMySQL 是开源的,所以你不需要支付额外的费用。\n\nMySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。\n\nMySQL 使用标准的 SQL 数据语言形式。\n\nMySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。\n\nMySQL 对PHP有很好的支持,PHP 是目前最流行的 Web 开发语言。\n\nMySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。\n\nMySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。\n', '4e3cb62d2aa7406e9b2b44da552968cb', '4e3cb62d2aa7406e9b2b44da552968cb.png', '2020-06-06 17:49:17', 2, 5),
('69e10cdd2851488bbf8ff4e6f6a602c1', 1000000, 'C++运行库64_86', 'C++ 运行库 64位 86位', '<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n<h3 id="c-64_86">C++运行库64_86</h3>\n', '###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86\n###C++运行库64_86', '69e10cdd2851488bbf8ff4e6f6a602c1', '69e10cdd2851488bbf8ff4e6f6a602c1.jpg', '2020-06-09 09:34:31', 2, 5),
('74d1f9675f6142f5844a102967ef3275', 1000000, '什么是面向对象编程?', '对象 C++ 编程', '<h1 id="-">面向对象程序设计 (一种计算机编程架构)</h1>\n<p><strong>同义词</strong> 面向对象编程一般指面向对象程序设计(一种计算机编程架构)</p>\n<p><strong>面向对象程序设计</strong>(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。\n中文名面向对象程序设计外文名Object Oriented Programming属 性计算机编程架构特 点具有<strong>重用性</strong>、<strong>灵活性</strong>和<strong>扩展性</strong></p>\n', '#面向对象程序设计 (一种计算机编程架构)\n**同义词** 面向对象编程一般指面向对象程序设计(一种计算机编程架构)\n\n**面向对象程序设计**(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。\n中文名面向对象程序设计外文名Object Oriented Programming属 性计算机编程架构特 点具有**重用性**、**灵活性**和**扩展性**', '74d1f9675f6142f5844a102967ef3275', '74d1f9675f6142f5844a102967ef3275.jpg', '2020-06-06 18:04:53', 2, 1),
('7a6bc5031674450d8c2628c829c60341', 1000000, '面试题之剪绳子', '面试 算法', '<p>给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]<em>k[1]</em>...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。</p>\n<p>示例 1:</p>\n<p>输入: 2\n输出: 1\n解释: 2 = 1 + 1, 1 × 1 = 1\n示例 2:</p>\n<p>输入: 10\n输出: 36\n解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36\n提示:</p>\n<p>2 <= n <= 58</p>\n<p>//思想是n长的绳子剪成m段(都是整数段),求每段乘起来的最大值\n//首先已知条件是m段分别长 k[0],k[1]...k[m-1],则k[0]+k[1]+...+k[m-1]=n,求 k[0]k[1]...k[m-1]\n//根据基本不等式(a+b)>=2倍的根号下(ab),得知每段长度相等就可以得到最大乘积,但因为每段是整数,所以每段就表示成(k+k'),k为整数部分,k'为小数部分\n//k=[n/m],k'=(n%m)/m,此时乘积\n// multi=(k+k')的m次方\n//把k取整,那么接下来就看n%m如何分配达到最大。因为n%m<m,要把剩余的n%m分配给m段,那么m个k'里至少有一个为0,k'就增大了,\n//此时乘积为\n// multi=k(k+k')的m-1次方\n//已经有一段固定为k,那么问题就变成了n-k长的绳子分成m-1段使得乘积最大,类似之前的根据基本不等式,每段值相等就可以得到最大。\n//因为n%m<m,可能是m-1,m-2......1,如果是m-1,那么直接平均分配给未固定的m-1段就可以得到最大,如果不是,照前面的思维递推,\n//得到m段的最大的乘积公式\n// multi=k的(m-n%m)次方*(k+1)的(n%m)次方\n//结论就是先把[n/m]长平均分配给m段,再把n%m长平均分配给n%m段就可以得到最大。\n//接下来用一个循环去求m从2到n 中的最大值就可以了</p>\n<pre><code class="lang-javascript">class Solution {\npublic:\n int cuttingRope(int n) {\n if(n<2||n>58) return 0;\n long int max_mul=0;\n for(int m=2;m<=n;m++)\n {\n int shang=n/m,yu=n%m;\n long int mul=pow(shang,m-yu)*pow(shang+1,yu);\n max_mul=max_mul>mul?max_mul:mul;\n }\n return max_mul;\n }\n};\n</code></pre>\n', '给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。\n\n示例 1:\n\n输入: 2\n输出: 1\n解释: 2 = 1 + 1, 1 × 1 = 1\n示例 2:\n\n输入: 10\n输出: 36\n解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36\n提示:\n\n2 <= n <= 58\n\n//思想是n长的绳子剪成m段(都是整数段),求每段乘起来的最大值\n//首先已知条件是m段分别长 k[0],k[1]...k[m-1],则k[0]+k[1]+...+k[m-1]=n,求 k[0]k[1]...k[m-1]\n//根据基本不等式(a+b)>=2倍的根号下(ab),得知每段长度相等就可以得到最大乘积,但因为每段是整数,所以每段就表示成(k+k\'),k为整数部分,k\'为小数部分\n//k=[n/m],k\'=(n%m)/m,此时乘积\n// multi=(k+k\')的m次方\n//把k取整,那么接下来就看n%m如何分配达到最大。因为n%m<m,要把剩余的n%m分配给m段,那么m个k\'里至少有一个为0,k\'就增大了,\n//此时乘积为\n// multi=k(k+k\')的m-1次方\n//已经有一段固定为k,那么问题就变成了n-k长的绳子分成m-1段使得乘积最大,类似之前的根据基本不等式,每段值相等就可以得到最大。\n//因为n%m<m,可能是m-1,m-2......1,如果是m-1,那么直接平均分配给未固定的m-1段就可以得到最大,如果不是,照前面的思维递推,\n//得到m段的最大的乘积公式\n// multi=k的(m-n%m)次方*(k+1)的(n%m)次方\n//结论就是先把[n/m]长平均分配给m段,再把n%m长平均分配给n%m段就可以得到最大。\n//接下来用一个循环去求m从2到n 中的最大值就可以了\n\n\n\n```javascript\nclass Solution {\npublic:\n int cuttingRope(int n) {\n if(n<2||n>58) return 0;\n long int max_mul=0;\n for(int m=2;m<=n;m++)\n {\n int shang=n/m,yu=n%m;\n long int mul=pow(shang,m-yu)*pow(shang+1,yu);\n max_mul=max_mul>mul?max_mul:mul;\n }\n return max_mul;\n }\n};\n```\n\n', NULL, NULL, '2020-06-08 15:01:40', 0, 2),
('7c4819b3525e4c94972ffb76ea406c0a', 1000002, 'C和C++关系', 'C C++ 关系', '<h2 id="c-c-">C和C++</h2>\n<p>C++是C的超集,也可以说C是C++的子集,因为C先出现。按常理说,C++编译器能够编译任何C程序,但是C和C++还是有一些小差别。</p>\n<p>例如C++增加了C不具有的关键字。这些关键字能作为函数和变量的标识符在C程序中使用,尽管C++包含了所有的C,但显然没有任何C++编译器能编译这样的C程序。</p>\n<p>C程序员可以省略函数原型,而C++不可以,一个不带参数的C函数原型必须把void写出来。而C++可以使用空参数列表。</p>\n<p>C++中new和delete是对内存分配的运算符,取代了C中的malloc和free。</p>\n<p>标准C++中的字符串类取代了C标准C函数库头文件中的字符数组处理函数(C中没有字符串类型)。</p>\n<p>C++中用来做控制态输入输出的iostream类库替代了标准C中的stdio函数库。</p>\n<p>C++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和longjmp()函数。</p>\n', '##C和C++\n\nC++是C的超集,也可以说C是C++的子集,因为C先出现。按常理说,C++编译器能够编译任何C程序,但是C和C++还是有一些小差别。\n\n例如C++增加了C不具有的关键字。这些关键字能作为函数和变量的标识符在C程序中使用,尽管C++包含了所有的C,但显然没有任何C++编译器能编译这样的C程序。\n\nC程序员可以省略函数原型,而C++不可以,一个不带参数的C函数原型必须把void写出来。而C++可以使用空参数列表。\n\nC++中new和delete是对内存分配的运算符,取代了C中的malloc和free。\n\n标准C++中的字符串类取代了C标准C函数库头文件中的字符数组处理函数(C中没有字符串类型)。\n\nC++中用来做控制态输入输出的iostream类库替代了标准C中的stdio函数库。\n\nC++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和longjmp()函数。', '7c4819b3525e4c94972ffb76ea406c0a', '7c4819b3525e4c94972ffb76ea406c0a.jpg', '2020-06-08 13:21:35', 0, 1),
('840bb8534867472087b66b76edc62105', 1000000, 'Docker虚拟机', 'Docker 虚拟机 安装包', '<h1 id="docker">Docker</h1>\n<p><strong>Docker</strong> 是一个開放原始碼軟體,是一個开放平台,用于开发应用、交付(shipping)应用、运行应用。 Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。</p>\n<p><strong>Docker</strong>容器 与虚拟机类似,但原理上,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。 容器更多的用于表示 软件的一个标准化单元。由于容器的标准化,因此它可以无视基础设施(Infrastructure)的差异,部署到任何一个地方。另外,Docker也为容器提供更强的业界的隔离兼容。</p>\n<p><strong>Docker </strong>利用Linux核心中的資源分離機制,例如cgroups,以及Linux核心命名空間(namespaces),來建立獨立的容器(containers)。這可以在單一Linux實體下運作,避免啟動一個虛擬機器造成的額外負擔[3]。Linux核心對命名空間的支援完全隔離了工作環境中應用程式的視野,包括行程樹、網路、用户ID與掛載檔案系統,而核心的cgroup提供资源隔離,包括CPU、記憶體、block I/O與網路。從0.9版本起,Dockers在使用抽象虛擬是經由libvirt的LXC與systemd - nspawn提供界面的基礎上,開始包括libcontainer函式庫做為以自己的方式開始直接使用由Linux核心提供的虛擬化的設施,</p>\n<p>依據行業分析公司「451研究」:「Dockers是有能力打包應用程式及其虛擬容器,可以在任何Linux伺服器上執行的依賴性工具,這有助於實現靈活性和便攜性,應用程式在任何地方都可以執行,無論是公用雲、私有雲、單機等。」</p>\n', '#Docker\n**Docker** 是一个開放原始碼軟體,是一個开放平台,用于开发应用、交付(shipping)应用、运行应用。 Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。\n\n**Docker**容器 与虚拟机类似,但原理上,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。 容器更多的用于表示 软件的一个标准化单元。由于容器的标准化,因此它可以无视基础设施(Infrastructure)的差异,部署到任何一个地方。另外,Docker也为容器提供更强的业界的隔离兼容。\n\n**Docker **利用Linux核心中的資源分離機制,例如cgroups,以及Linux核心命名空間(namespaces),來建立獨立的容器(containers)。這可以在單一Linux實體下運作,避免啟動一個虛擬機器造成的額外負擔[3]。Linux核心對命名空間的支援完全隔離了工作環境中應用程式的視野,包括行程樹、網路、用户ID與掛載檔案系統,而核心的cgroup提供资源隔離,包括CPU、記憶體、block I/O與網路。從0.9版本起,Dockers在使用抽象虛擬是經由libvirt的LXC與systemd - nspawn提供界面的基礎上,開始包括libcontainer函式庫做為以自己的方式開始直接使用由Linux核心提供的虛擬化的設施,\n\n依據行業分析公司「451研究」:「Dockers是有能力打包應用程式及其虛擬容器,可以在任何Linux伺服器上執行的依賴性工具,這有助於實現靈活性和便攜性,應用程式在任何地方都可以執行,無論是公用雲、私有雲、單機等。」', '840bb8534867472087b66b76edc62105', '840bb8534867472087b66b76edc62105.png', '2020-06-07 14:15:49', 0, 5),
('8713632e9614452d845b637973e488fd', 1000002, '三目运算符', '三目运算符 C++', '<h1 id="-">三目运算符</h1>\n<p>三目运算符,又称条件运算符,是计算机语言(c,c++,java等)的重要组成部分。它是唯一有3个操作数的运算符,有时又称为三元运算符。一般来说,三目运算符的结合性是右结合的。</p>\n<h2 id="-">定义</h2>\n<p>对于条件表达式b ? x : y,先计算条件b,然后进行判断。如果b的值为true,计算x的值,运算结果为x的值;否则,计算y的值,运算结果为y的值。一个条件表达式绝不会既计算x,又计算y。条件运算符是右结合的,也就是说,从右向左分组计算。例如,a ? b : c ? d : e将按a ? b : (c ? d : e)执行。 [1] \n<表达式1> ? <表达式2> : <表达式3>; "?"运算符的含义是:先求表达式1的值,如果为真,则执行表达式2,并返回表达式2的结果;如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。\n可以理解为条件 ? 结果1 : 结果2 里面的?号是格式要求。也可以理解为条件是否成立,条件成立为结果1,否则为结果2。\n注意:在C语言中,结果1 和 结果2的类型必须一致。\na ? b : c简单理解方式为:</p>\n<pre><code class="lang-javascript">if(a) {\n\n\n return b;\n\n\n} else {\n\n\n return c;\n\n\n}\n</code></pre>\n', '#三目运算符 \n三目运算符,又称条件运算符,是计算机语言(c,c++,java等)的重要组成部分。它是唯一有3个操作数的运算符,有时又称为三元运算符。一般来说,三目运算符的结合性是右结合的。\n##定义\n对于条件表达式b ? x : y,先计算条件b,然后进行判断。如果b的值为true,计算x的值,运算结果为x的值;否则,计算y的值,运算结果为y的值。一个条件表达式绝不会既计算x,又计算y。条件运算符是右结合的,也就是说,从右向左分组计算。例如,a ? b : c ? d : e将按a ? b : (c ? d : e)执行。 [1] \n<表达式1> ? <表达式2> : <表达式3>; "?"运算符的含义是:先求表达式1的值,如果为真,则执行表达式2,并返回表达式2的结果;如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。\n可以理解为条件 ? 结果1 : 结果2 里面的?号是格式要求。也可以理解为条件是否成立,条件成立为结果1,否则为结果2。\n注意:在C语言中,结果1 和 结果2的类型必须一致。\na ? b : c简单理解方式为:\n\n\n\n```javascript\nif(a) {\n \n \n return b;\n \n \n} else {\n \n \n return c;\n \n \n}\n\n```', '8713632e9614452d845b637973e488fd', '8713632e9614452d845b637973e488fd.jpg', '2020-06-08 13:25:07', 1, 1),
('96169ff1654347d7912791e74c3cab80', 1000002, 'C++ Web 编程', 'C++ Web 编程', '<p>C++ Web 编程\n什么是 CGI?\n公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。\nCGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI 如下:\n公共网关接口(CGI),是一种用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准。\n目前的版本是 CGI/1.1,CGI/1.2 版本正在推进中。\nWeb 浏览\n为了更好地了解 CGI 的概念,让我们点击一个超链接,浏览一个特定的网页或 URL,看看会发生什么。</p>\n<p>您的浏览器联系上 HTTP Web 服务器,并请求 URL,即文件名。\nWeb 服务器将解析 URL,并查找文件名。如果找到请求的文件,Web 服务器会把文件发送回浏览器,否则发送一条错误消息,表明您请求了一个错误的文件。\nWeb 浏览器从 Web 服务器获取响应,并根据接收到的响应来显示文件或错误消息。\n然而,以这种方式搭建起来的 HTTP 服务器,不管何时请求目录中的某个文件,HTTP 服务器发送回来的不是该文件,而是以程序形式执行,并把执行产生的输出发送回浏览器显示出来。</p>\n<p>公共网关接口(CGI),是使得应用程序(称为 CGI 程序或 CGI 脚本)能够与 Web 服务器以及客户端进行交互的标准协议。这些 CGI 程序可以用 Python、PERL、Shell、C 或 C++ 等进行编写。</p>\n', 'C++ Web 编程\n什么是 CGI?\n公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。\nCGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI 如下:\n公共网关接口(CGI),是一种用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准。\n目前的版本是 CGI/1.1,CGI/1.2 版本正在推进中。\nWeb 浏览\n为了更好地了解 CGI 的概念,让我们点击一个超链接,浏览一个特定的网页或 URL,看看会发生什么。\n\n您的浏览器联系上 HTTP Web 服务器,并请求 URL,即文件名。\nWeb 服务器将解析 URL,并查找文件名。如果找到请求的文件,Web 服务器会把文件发送回浏览器,否则发送一条错误消息,表明您请求了一个错误的文件。\nWeb 浏览器从 Web 服务器获取响应,并根据接收到的响应来显示文件或错误消息。\n然而,以这种方式搭建起来的 HTTP 服务器,不管何时请求目录中的某个文件,HTTP 服务器发送回来的不是该文件,而是以程序形式执行,并把执行产生的输出发送回浏览器显示出来。\n\n公共网关接口(CGI),是使得应用程序(称为 CGI 程序或 CGI 脚本)能够与 Web 服务器以及客户端进行交互的标准协议。这些 CGI 程序可以用 Python、PERL、Shell、C 或 C++ 等进行编写。', NULL, NULL, '2020-06-08 14:35:07', 0, 2),
('990b01c7f6574561ab881b2a2fbe92d0', 1000002, 'C++ 动态内存', '动态内存', '<p>C++ 动态内存\n了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:</p>\n<p>栈:在函数内部声明的所有变量都将占用栈内存。\n堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。\n很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。</p>\n<p>在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。</p>\n<p>如果您不需要动态分配内存,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。</p>\n<p>new 和 delete 运算符\n下面是使用 new 运算符来为任意的数据类型动态分配内存的通用语法:</p>\n<p>new data-type;\n在这里,data-type 可以是包括数组在内的任意内置的数据类型,也可以是包括类或结构在内的用户自定义的任何数据类型。让我们先来看下内置的数据类型。例如,我们可以定义一个指向 double 类型的指针,然后请求内存,该内存在执行时被分配。我们可以按照下面的语句使用 new 运算符来完成这点:</p>\n<p>double* pvalue = NULL; // 初始化为 null 的指针\npvalue = new double; // 为变量请求内存\n如果自由存储区已被用完,可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针,并采取以下适当的操作:</p>\n<p>double* pvalue = NULL;\nif( !(pvalue = new double ))\n{\n cout << "Error: out of memory." <<endl;\n exit(1);</p>\n<p>}\nmalloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。</p>\n<p>在任何时候,当您觉得某个已经动态分配内存的变量不再需要使用时,您可以使用 delete 操作符释放它所占用的内存,如下所示:</p>\n', 'C++ 动态内存\n了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:\n\n栈:在函数内部声明的所有变量都将占用栈内存。\n堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。\n很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。\n\n在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。\n\n如果您不需要动态分配内存,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。\n\nnew 和 delete 运算符\n下面是使用 new 运算符来为任意的数据类型动态分配内存的通用语法:\n\nnew data-type;\n在这里,data-type 可以是包括数组在内的任意内置的数据类型,也可以是包括类或结构在内的用户自定义的任何数据类型。让我们先来看下内置的数据类型。例如,我们可以定义一个指向 double 类型的指针,然后请求内存,该内存在执行时被分配。我们可以按照下面的语句使用 new 运算符来完成这点:\n\ndouble* pvalue = NULL; // 初始化为 null 的指针\npvalue = new double; // 为变量请求内存\n如果自由存储区已被用完,可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针,并采取以下适当的操作:\n\n\ndouble* pvalue = NULL;\nif( !(pvalue = new double ))\n{\n cout << "Error: out of memory." <<endl;\n exit(1);\n\n}\nmalloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。\n\n在任何时候,当您觉得某个已经动态分配内存的变量不再需要使用时,您可以使用 delete 操作符释放它所占用的内存,如下所示:', NULL, NULL, '2020-06-08 14:35:28', 1, 2),
('9f5b8f3eaecb4296910f0f39d65cef5d', 1000002, '图解HTTP.pdf', 'HTTP 协议 图解 PDF', '<h2 id="-">目录</h2>\n<h3 id="-1-web-001">第1章 了解Web及网络基础 001</h3>\n<p>1.1 使用HTTP协议访问Web 002</p>\n<p>1.2 HTTP的诞生003</p>\n<p>1.2.1 为知识共享而规划Web 003</p>\n<p>1.2.2 Web成长时代 004</p>\n<p>1.2.3 驻足不前的HTTP 005</p>\n<p>1.3 网络基础TCP/IP 006</p>\n<p>1.3.1 TCP/IP协议族 006</p>\n<p>1.3.2 TCP/IP的分层管理 007</p>\n<p>1.3.3 TCP/IP通信传输流 009</p>\n<p>1.4 与HTTP关系密切的协议:IP、TCP和DNS 010</p>\n<p>1.4.1 负责传输的IP协议 011</p>\n<p>1.4.2 确保可靠性的TCP协议 012</p>\n<p>1.5 负责域名解析的DNS服务 013</p>\n<p>1.6 各种协议与HTTP协议的关系 014</p>\n<p>1.7 URI和URL 016</p>\n<p>1.7.1 统一资源标识符 016</p>\n<p>1.7.2 URI格式 017</p>\n<h3 id="-2-http-021">第2章 简单的HTTP协议 021</h3>\n<p>2.1 HTTP协议用于客户端和服务器端之间的通信 022</p>\n<p>2.2 通过请求和响应的交换达成通信 022</p>\n<p>2.3 HTTP是不保存状态的协议 025</p>\n<p>2.4 请求URI定位资源 026</p>\n<p>2.5 告知服务器意图的HTTP 方法027</p>\n<p>2.6 使用方法下达命令 033</p>\n<p>2.7 持久连接节省通信量 034</p>\n<p>2.7.1 持久连接 036</p>\n<p>2.7.2 管线化 037</p>\n<p>2.8 使用Cookie的状态管理 037</p>\n<h3 id="-3-http-http-041">第3章HTTP报文内的HTTP信息 041</h3>\n<p>3.1HTTP报文 042</p>\n<p>3.2 请求报文及响应报文的结构 042</p>\n<p>3.3 编码提升传输速率 044</p>\n<p>3.3.1 报文主体和实体主体的差异 044</p>\n<p>3.3.2 压缩传输的内容编码 044</p>\n<p>3.3.3 分割发送的分块传输编码 045</p>\n<p>3.4 发送多种数据的多部分对象集合 046</p>\n<p>3.5 获取部分内容的范围请求048</p>\n<p>3.6 内容协商返回最合适的内容050</p>\n<h3 id="-4-http-053">第4章 返回结果的HTTP状态码 053</h3>\n<p>4.1 状态码告知从服务器端返回的请求结果054</p>\n<p>4.2 2XX成功 055</p>\n<p>4.2.1 200 OK 055</p>\n<p>4.2.2 204 No Content 056</p>\n<p>4.2.3 206 Partial Content 056</p>\n<p>4.3 3XX 重定向 056</p>\n<p>4.3.1 301 Moved Permanently 057</p>\n<p>4.3.2 302 Found 057</p>\n<p>4.3.3 303 See Other 058</p>\n<p>4.3.4 304 Not Modified 059</p>\n<p>4.3.5 307 Temporary Redirect 059</p>\n<p>4.4 4XX 客户端错误 060</p>\n<p>4.4.1 400 Bad Request 060</p>\n<p>4.4.2 401 Unauthorized 060</p>\n<p>4.4.3 403 Forbidden 061</p>\n<p>4.4.4 404 Not Found 061</p>\n<p>4.5 5XX 服务器错误 062</p>\n<p>4.5.1 500 Internal Server Error 062</p>\n<p>4.5.2 503 Service Unavailable 062</p>\n<h3 id="-5-http-web-065">第5章 与HTTP协作的Web服务器 065</h3>\n<p>5.1 用单台虚拟主机实现多个域名 066</p>\n<p>5.2 通信数据转发程序:代理、网关、隧道 067</p>\n<p>5.2.1 代理 068</p>\n<p>5.2.2 网关 070</p>\n<p>5.2.3 隧道 070</p>\n<p>5.3 保存资源的缓存 071</p>\n<p>5.3.1 缓存的有效期限 072</p>\n<p>5.3.2 客户端的缓存 072</p>\n<p>第6章 HTTP 首部 075</p>\n<p>6.1 HTTP 报文首部 076</p>\n<p>6.2 HTTP 首部字段 078</p>\n<p>6.2.1 HTTP首部字段传递重要信息 078</p>\n<p>6.2.2 HTTP首部字段结构 078</p>\n<p>6.2.3 4种HTTP首部字段类型 079</p>\n<p>6.2.4 HTTP/1.1首部字段一览 080</p>\n<p>6.2.5 非HTTP/1.1首部字段 082</p>\n<p>6.2.6 End-to-end首部和Hop-by-hop首部 083</p>\n<p>6.3 HTTP/1.1 通用首部字段 083</p>\n<p>6.3.1 Cache-Control 084</p>\n<p>6.3.2 Connection 091</p>\n<p>6.3.3 Date 093</p>\n<p>6.3.4 Pragma 094</p>\n<p>6.3.5 Trailer 095</p>\n<p>6.3.6 Transfer-Encoding 096</p>\n<p>6.3.7 Upgrade 097</p>\n<p>6.3.8 Via 098</p>\n<p>6.3.9 Warning 099</p>\n<p>6.4 请求首部字段 100</p>\n<p>6.4.1 Accept 101</p>\n<p>6.4.2 Accept-Charset 102</p>\n<p>6.4.3 Accept-Encoding 103</p>\n<p>6.4.4 Accept-Language 104</p>\n<p>6.4.5 Authorization 105</p>\n<p>6.4.6 Expect 106</p>\n<p>6.4.7 From 107</p>\n<p>6.4.8 Host 107</p>\n<p>6.4.9 If-Match 108</p>\n<p>6.4.10 If-Modified-Since 110</p>\n<p>6.4.11 If-None-Match 111</p>\n<p>6.4.12 If-Range 112</p>\n<p>6.4.13 If-Unmodified-Since 113</p>\n<p>6.4.14 Max-Forwards 114</p>\n<p>6.4.15 Proxy-Authorization 115</p>\n<p>6.4.16 Range 116</p>\n<p>6.4.17 Referer 116</p>\n<p>6.4.18 TE 117</p>\n<p>6.4.19 User-Agent 118</p>\n<p>6.5 响应首部字段119</p>\n<p>6.5.1 Accept-Ranges 119</p>\n<p>6.5.2 Age 120</p>\n<p>6.5.3 ETag 120</p>\n<p>6.5.4 Location 122</p>\n<p>6.5.5 Proxy-Authenticate 123</p>\n<p>6.5.6 Retry-After 123</p>\n<p>6.5.7 Server 124</p>\n<p>6.5.8 Vary 125</p>\n<p>6.5.9 WWW-Authenticate 125</p>\n<p>6.6 实体首部字段126</p>\n<p>6.6.1 Allow 126</p>\n<p>6.6.2 Content-Encoding 127</p>\n<p>6.6.3 Content-Language 128</p>\n<p>6.6.4 Content-Length 128</p>\n<p>6.6.5 Content-Location 129</p>\n<p>6.6.6 Content-MD5 129</p>\n<p>6.6.7 Content-Range 130</p>\n<p>6.6.8 Content-Type 131</p>\n<p>6.6.9 Expires 131</p>\n<p>6.6.10 Last-Modified 132</p>\n<p>6.7 为Cookie服务的首部字段 132</p>\n<p>6.7.1 Set-Cookie 134</p>\n<p>6.7.2 Cookie 136</p>\n<p>6.8 其他首部字段137</p>\n<p>6.8.1 X-Frame-Options 137</p>\n<p>6.8.2 X-XSS-Protection 138</p>\n<p>6.8.3 DNT 138</p>\n<p>6.8.4 P3P 139</p>\n<p>.........</p>\n', '##目录\n###第1章 了解Web及网络基础 001\n\n1.1 使用HTTP协议访问Web 002\n\n1.2 HTTP的诞生003\n\n1.2.1 为知识共享而规划Web 003\n\n1.2.2 Web成长时代 004\n\n1.2.3 驻足不前的HTTP 005\n\n1.3 网络基础TCP/IP 006\n\n1.3.1 TCP/IP协议族 006\n\n1.3.2 TCP/IP的分层管理 007\n\n1.3.3 TCP/IP通信传输流 009\n\n1.4 与HTTP关系密切的协议:IP、TCP和DNS 010\n\n1.4.1 负责传输的IP协议 011\n\n1.4.2 确保可靠性的TCP协议 012\n\n1.5 负责域名解析的DNS服务 013\n\n1.6 各种协议与HTTP协议的关系 014\n\n1.7 URI和URL 016\n\n1.7.1 统一资源标识符 016\n\n1.7.2 URI格式 017\n\n###第2章 简单的HTTP协议 021\n\n2.1 HTTP协议用于客户端和服务器端之间的通信 022\n\n2.2 通过请求和响应的交换达成通信 022\n\n2.3 HTTP是不保存状态的协议 025\n\n2.4 请求URI定位资源 026\n\n2.5 告知服务器意图的HTTP 方法027\n\n2.6 使用方法下达命令 033\n\n2.7 持久连接节省通信量 034\n\n2.7.1 持久连接 036\n\n2.7.2 管线化 037\n\n2.8 使用Cookie的状态管理 037\n\n###第3章HTTP报文内的HTTP信息 041\n\n3.1HTTP报文 042\n\n3.2 请求报文及响应报文的结构 042\n\n3.3 编码提升传输速率 044\n\n3.3.1 报文主体和实体主体的差异 044\n\n3.3.2 压缩传输的内容编码 044\n\n3.3.3 分割发送的分块传输编码 045\n\n3.4 发送多种数据的多部分对象集合 046\n\n3.5 获取部分内容的范围请求048\n\n3.6 内容协商返回最合适的内容050\n\n###第4章 返回结果的HTTP状态码 053\n\n4.1 状态码告知从服务器端返回的请求结果054\n\n4.2 2XX成功 055\n\n4.2.1 200 OK 055\n\n4.2.2 204 No Content 056\n\n4.2.3 206 Partial Content 056\n\n4.3 3XX 重定向 056\n\n4.3.1 301 Moved Permanently 057\n\n4.3.2 302 Found 057\n\n4.3.3 303 See Other 058\n\n4.3.4 304 Not Modified 059\n\n4.3.5 307 Temporary Redirect 059\n\n4.4 4XX 客户端错误 060\n\n4.4.1 400 Bad Request 060\n\n4.4.2 401 Unauthorized 060\n\n4.4.3 403 Forbidden 061\n\n4.4.4 404 Not Found 061\n\n4.5 5XX 服务器错误 062\n\n4.5.1 500 Internal Server Error 062\n\n4.5.2 503 Service Unavailable 062\n\n###第5章 与HTTP协作的Web服务器 065\n\n5.1 用单台虚拟主机实现多个域名 066\n\n5.2 通信数据转发程序:代理、网关、隧道 067\n\n5.2.1 代理 068\n\n5.2.2 网关 070\n\n5.2.3 隧道 070\n\n5.3 保存资源的缓存 071\n\n5.3.1 缓存的有效期限 072\n\n5.3.2 客户端的缓存 072\n\n第6章 HTTP 首部 075\n\n6.1 HTTP 报文首部 076\n\n6.2 HTTP 首部字段 078\n\n6.2.1 HTTP首部字段传递重要信息 078\n\n6.2.2 HTTP首部字段结构 078\n\n6.2.3 4种HTTP首部字段类型 079\n\n6.2.4 HTTP/1.1首部字段一览 080\n\n6.2.5 非HTTP/1.1首部字段 082\n\n6.2.6 End-to-end首部和Hop-by-hop首部 083\n\n6.3 HTTP/1.1 通用首部字段 083\n\n6.3.1 Cache-Control 084\n\n6.3.2 Connection 091\n\n6.3.3 Date 093\n\n6.3.4 Pragma 094\n\n6.3.5 Trailer 095\n\n6.3.6 Transfer-Encoding 096\n\n6.3.7 Upgrade 097\n\n6.3.8 Via 098\n\n6.3.9 Warning 099\n\n6.4 请求首部字段 100\n\n6.4.1 Accept 101\n\n6.4.2 Accept-Charset 102\n\n6.4.3 Accept-Encoding 103\n\n6.4.4 Accept-Language 104\n\n6.4.5 Authorization 105\n\n6.4.6 Expect 106\n\n6.4.7 From 107\n\n6.4.8 Host 107\n\n6.4.9 If-Match 108\n\n6.4.10 If-Modified-Since 110\n\n6.4.11 If-None-Match 111\n\n6.4.12 If-Range 112\n\n6.4.13 If-Unmodified-Since 113\n\n6.4.14 Max-Forwards 114\n\n6.4.15 Proxy-Authorization 115\n\n6.4.16 Range 116\n\n6.4.17 Referer 116\n\n6.4.18 TE 117\n\n6.4.19 User-Agent 118\n\n6.5 响应首部字段119\n\n6.5.1 Accept-Ranges 119\n\n6.5.2 Age 120\n\n6.5.3 ETag 120\n\n6.5.4 Location 122\n\n6.5.5 Proxy-Authenticate 123\n\n6.5.6 Retry-After 123\n\n6.5.7 Server 124\n\n6.5.8 Vary 125\n\n6.5.9 WWW-Authenticate 125\n\n6.6 实体首部字段126\n\n6.6.1 Allow 126\n\n6.6.2 Content-Encoding 127\n\n6.6.3 Content-Language 128\n\n6.6.4 Content-Length 128\n\n6.6.5 Content-Location 129\n\n6.6.6 Content-MD5 129\n\n6.6.7 Content-Range 130\n\n6.6.8 Content-Type 131\n\n6.6.9 Expires 131\n\n6.6.10 Last-Modified 132\n\n6.7 为Cookie服务的首部字段 132\n\n6.7.1 Set-Cookie 134\n\n6.7.2 Cookie 136\n\n6.8 其他首部字段137\n\n6.8.1 X-Frame-Options 137\n\n6.8.2 X-XSS-Protection 138\n\n6.8.3 DNT 138\n\n6.8.4 P3P 139\n\n.........', '9f5b8f3eaecb4296910f0f39d65cef5d', '9f5b8f3eaecb4296910f0f39d65cef5d.jpg', '2020-06-08 13:40:14', 1, 4),
('a8dad06ce448473ea5408bfdfbb73343', 1000002, 'HelloWorld源码', 'C++ 源码 入门', '<p>一个非常简单的程序。</p>\n<p>希望这个程序能点燃你的兴趣!</p>\n', '一个非常简单的程序。\n\n希望这个程序能点燃你的兴趣!', 'a8dad06ce448473ea5408bfdfbb73343', 'a8dad06ce448473ea5408bfdfbb73343.png', '2020-06-08 14:31:05', 2, 6),
('aa8fb6d525e84b83af68f09e819de4fa', 1000002, 'struts类型加强', 'struts 类型 C++', '<p>结构体定义 typedefstruct 用法详解和用法小结</p>\n<p>typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。</p>\n<p>具体区别在于:</p>\n<p>若struct node{}这样来定义结构体的话。在申请node的变量时,需要这样写,struct node n;</p>\n<p>若用typedef,可以这样写,typedef struct node{}NODE; 。在申请变量时就可以这样写,NODE n;</p>\n<p>区别就在于使用时,是否可以省去struct这个关键字。</p>\n<p>第三篇:struct和typedef struct</p>\n<p>分三块来讲述:</p>\n<p>1 首先:</p>\n<p>在C中定义一个结构体类型要用typedef:</p>\n<pre><code class="lang-javascript">typedef struct Student\n\n{\n\nint a;\n\n}Stu;\n</code></pre>\n<p>于是在声明变量的时候就可:Stustu1;</p>\n<p>如果没有typedef就必须用struct Student stu1;来声明</p>\n<p>这里的Stu实际上就是struct Student的别名。</p>\n', '结构体定义 typedefstruct 用法详解和用法小结\n\n\n\ntypedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。\n\n具体区别在于:\n\n若struct node{}这样来定义结构体的话。在申请node的变量时,需要这样写,struct node n;\n\n若用typedef,可以这样写,typedef struct node{}NODE; 。在申请变量时就可以这样写,NODE n;\n\n区别就在于使用时,是否可以省去struct这个关键字。\n\n \n\n第三篇:struct和typedef struct\n\n分三块来讲述:\n\n1 首先:\n\n在C中定义一个结构体类型要用typedef:\n\n\n\n```javascript\ntypedef struct Student\n\n{\n\nint a;\n\n}Stu;\n\n```\n于是在声明变量的时候就可:Stustu1;\n\n如果没有typedef就必须用struct Student stu1;来声明\n\n这里的Stu实际上就是struct Student的别名。\n', 'aa8fb6d525e84b83af68f09e819de4fa', 'aa8fb6d525e84b83af68f09e819de4fa.jpg', '2020-06-08 13:32:04', 1, 1),
('c6ddbe9340d6436f816a66fc8d0a54ad', 1000000, 'C++入门之HelloWorld', 'C++ 入门 HelloWorld', '<h2 id="c-hello-world-">C++ 实例 - 输出 "Hello, World!"</h2>\n<p>C++ 实例\n使用 C++ 输出字符串 "Hello, World!",只是一个简单的入门实例,需要使用 main() 函数及标准输出 cout:</p>\n<p>实例</p>\n<pre><code class="lang-javascript">#include <iostream>\nusing namespace std;\n\nint main() \n{\n cout << "Hello, World!";\n return 0;\n}\n</code></pre>\n<p>以上程序执行输出结果为:</p>\n<p><strong>Hello, World!</strong></p>\n', '##C++ 实例 - 输出 "Hello, World!"\nC++ 实例\n使用 C++ 输出字符串 "Hello, World!",只是一个简单的入门实例,需要使用 main() 函数及标准输出 cout:\n\n实例\n\n\n```javascript\n#include <iostream>\nusing namespace std;\n \nint main() \n{\n cout << "Hello, World!";\n return 0;\n}\n```\n以上程序执行输出结果为:\n\n**Hello, World!**', 'c6ddbe9340d6436f816a66fc8d0a54ad', 'c6ddbe9340d6436f816a66fc8d0a54ad.png', '2020-06-03 08:42:36', 15, 1),
('c9ef528271954b5ea262113524b53253', 1000000, 'C++内存管理机制', 'C++ 内存管理', '<h2 id="1-">1.从内存对齐讲起</h2>\n<p><strong>对于结构体变量内存对齐遵循以下三个原则:</strong></p>\n<p>变量的起始地址能够被其对齐值整除,结构体变量的对齐值为最宽的成员大小。\n结构体每个成员相对于起始地址的偏移能够被其自身对齐值整除,如果不能则在前一个成员后面补充字节。\n结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节。\n此外还有编译器的默认对齐值,一般默认对齐值为4(结构体的实际对齐值会取结构体对齐值和编译器默认对齐值中较小的那一个)。</p>\n<p><strong>那么为什么要内存对齐?</strong></p>\n<p>为了减少使用的内存\n为了提升数据读取的效率\n考虑以下的结构体:</p>\n<pre><code class="lang-javascript">struct Test\n{\n char a;\n int b;\n short c;\n};\n</code></pre>\n<p>C++中可以使用alignof获取类型的对齐值,char类型的对齐值为1, int的对齐值为4, short的对齐值为2,整个结构体的对齐值为4。假设结构体变量的起始地址已经对齐,那么结构体的第一个成员a已经对齐,由于第一个成员a的大小为1而第二成员b的对齐值为4,则根据第二条对齐原则需要在第一个成员后填充3个字节才能使第二个成员对齐,第二个成员对齐后第三个成员的起始地址刚好为其对齐值的整数倍所以不需要进行填充,此时算上填充字节,结构体占用的总字节为10字节,又由第三条原则,结构体大小需要为4的整数倍,因此需要在第三个成员c后填充2个字节,可以算得结构体的总大小为12(在默认对齐值为2时,大小为8字节)。</p>\n<p><strong>改变结构体成员顺序如下:</strong></p>\n<pre><code class="lang-javascript">struct Test\n{\n int b;\n short c;\n char a;\n};\n</code></pre>\n<p>改变成员顺序后,若结构体变量的起始地址已经对齐,则根据原则2三个成员均以对齐,中间不需要进行填充,此时结构体占用的总字节为7,又由原则3需要在最后一个变量后填充1个字节,因此结构体总大小为8(在默认对齐值为2时,大小也为8字节)。</p>\n<p>从上面的例子可以看出根据对齐原则合理安排结构体成员的顺序可以减少内存的占用。</p>\n<p>现在考虑一个double类型的数组(double类型为8字节对齐), 其在内存中所处的位置如下:\n<img src="https://pic2.zhimg.com/80/v2-3d140e576a3a02e4c8cf9df2b3800cb5_720w.jpg" alt="图片">\n数组的首地址为2,根据原则1数组未对齐。若CPU每次从内存中为8字节整数倍的地址开始读入8字节的数据,则每次从未对齐的数组中读取一个成员都要进行两次读取操作,而从对齐的数组中读取则只需要一次读取操作,数组对齐时读取效率有较大提升(虽然现在也有很多处理器支持非对齐的读取,但是还是推荐对齐)。</p>\n', '##1.从内存对齐讲起\n\n**对于结构体变量内存对齐遵循以下三个原则:**\n\n变量的起始地址能够被其对齐值整除,结构体变量的对齐值为最宽的成员大小。\n结构体每个成员相对于起始地址的偏移能够被其自身对齐值整除,如果不能则在前一个成员后面补充字节。\n结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节。\n此外还有编译器的默认对齐值,一般默认对齐值为4(结构体的实际对齐值会取结构体对齐值和编译器默认对齐值中较小的那一个)。\n\n**那么为什么要内存对齐?**\n\n为了减少使用的内存\n为了提升数据读取的效率\n考虑以下的结构体:\n\n\n\n```javascript\nstruct Test\n{\n char a;\n int b;\n short c;\n};\n```\n\nC++中可以使用alignof获取类型的对齐值,char类型的对齐值为1, int的对齐值为4, short的对齐值为2,整个结构体的对齐值为4。假设结构体变量的起始地址已经对齐,那么结构体的第一个成员a已经对齐,由于第一个成员a的大小为1而第二成员b的对齐值为4,则根据第二条对齐原则需要在第一个成员后填充3个字节才能使第二个成员对齐,第二个成员对齐后第三个成员的起始地址刚好为其对齐值的整数倍所以不需要进行填充,此时算上填充字节,结构体占用的总字节为10字节,又由第三条原则,结构体大小需要为4的整数倍,因此需要在第三个成员c后填充2个字节,可以算得结构体的总大小为12(在默认对齐值为2时,大小为8字节)。\n\n**改变结构体成员顺序如下:**\n\n\n\n```javascript\nstruct Test\n{\n int b;\n short c;\n char a;\n};\n```\n\n改变成员顺序后,若结构体变量的起始地址已经对齐,则根据原则2三个成员均以对齐,中间不需要进行填充,此时结构体占用的总字节为7,又由原则3需要在最后一个变量后填充1个字节,因此结构体总大小为8(在默认对齐值为2时,大小也为8字节)。\n\n从上面的例子可以看出根据对齐原则合理安排结构体成员的顺序可以减少内存的占用。\n\n现在考虑一个double类型的数组(double类型为8字节对齐), 其在内存中所处的位置如下:\n![图片](https://pic2.zhimg.com/80/v2-3d140e576a3a02e4c8cf9df2b3800cb5_720w.jpg)\n数组的首地址为2,根据原则1数组未对齐。若CPU每次从内存中为8字节整数倍的地址开始读入8字节的数据,则每次从未对齐的数组中读取一个成员都要进行两次读取操作,而从对齐的数组中读取则只需要一次读取操作,数组对齐时读取效率有较大提升(虽然现在也有很多处理器支持非对齐的读取,但是还是推荐对齐)。', 'c9ef528271954b5ea262113524b53253', 'c9ef528271954b5ea262113524b53253.jpg', '2020-06-03 09:05:57', 8, 1),
('d0b02c0501f6404aa9d354c5614b2981', 1000002, '程序一定要从main函数开始运行吗?', 'Main 函数 主函数', '<p>程序一定要从main函数开始运行吗?本文涉及静态链接相关知识。</p>\n<p>对于静态链接先提出两个问题:</p>\n<p>Q:每个目标文件都有好多个段,目标文件在被链接成可执行文件时,输入目标文件中的各个段如何被合并到输出文件?</p>\n<p>A:合并相似的段,将所有的.text段合并到输出文件的.text段,将所有的.data段合并到输出文件的.data段。</p>\n<p>Q:链接器如何为他们分配在输出文件中的空间和地址?</p>\n<p>A:这里涉及到程序链接的两个步骤:</p>\n<p>空间与地址分配:扫描所有的输入目标文件,获得它们每个段的长度属性和位置,收集输入目标文件中的符号表中的所有符号定义和符号引用,统一放到一个全局符号表中,合并所有的段,计算出输出文件中各个段合并后的长度和位置,并建立映射关系。\n符号解析与重定位:使用第一步收集到的所有信息,读取输入文件中段的数据及重定位信息,进行符号解析和重定位,调整代码中的地址,将每个段中需要重定位的指令和数据进行“修补”,使他们都指向正确的位置。\ntips:外部符号指的是目标文件需要引用的符号,但是定义在其它目标文件中,链接前外部符号地址都是000000之类,链接后的可执行文件就可以看见这些外部符号都是有地址的。链接就是把相似的段放在一起,先找到段的偏移地址,再找出符号在段中的偏移,这样可以确定符号在整个可执行程序中的地址。</p>\n<p>对于那些需要重定位的符号,都会放在重定位表里,也叫重定位段,即.rel.data、.rel.text等,如果.text段有被重定位的地方,就有.rel.text段,如果.data段有被重定位的地方,就有.rel.data段。可以使用objdump查看目标文件的重定位表。</p>\n<p><strong>源代码:</strong></p>\n<pre><code class="lang-javascript">int main() {\n printf("程序喵\\n");\n return 0;\n}\ngcc -c test\nobjdump -r test.o\n\ntest.o: file format elf64-x86-64\n\nRELOCATION RECORDS FOR [.text]:\nOFFSET TYPE VALUE\n0000000000000007 R_X86_64_PC32 .rodata-0x0000000000000004\n000000000000000c R_X86_64_PLT32 puts-0x0000000000000004\n\n\nRELOCATION RECORDS FOR [.eh_frame]:\nOFFSET TYPE VALUE\n0000000000000020 R_X86_64_PC32 .text\n</code></pre>\n<p>使用nm也可以查看需要重定位的符号:</p>\n<pre><code class="lang-javascript">nm -u test.o\n U _GLOBAL_OFFSET_TABLE_\n U puts\n</code></pre>\n<p>对于UND类型,这种未定义的符号都是因为该目标文件中有关于他们的重定位项,在链接器扫描完所有的输入目标文件后,所有这种未定义的符号都应该能在全局符号表中找到,否则报符号未定义错误。</p>\n<p>注意:我们代码里明明用的是printf,为什么它却引用了puts的符号呢,因为编译器默认情况下会把只用一个字符串参数的printf替换成puts, 可以节省格式解析的时间,使用-fno-builtin会关闭这个内置函数优化选项,如下:</p>\n<pre><code class="lang-javascript">~/test$ gcc -c -fno-builtin testlink.cc -o test.o\n~/test$ nm test.o\n U _GLOBAL_OFFSET_TABLE_\n0000000000000000 T main\n U printf\n</code></pre>\n<p>tips:现在的程序和库通常来讲都很大,一个目标文件可能包含成百上千个函数或变量,当需要用到某个目标文件的任意一个函数或变量时,就需要把它整个目标文件都链接进来,也就是说那些没有用到的函数也会被链接进去,这会导致链接输出文件变的很大,造成空间浪费。</p>\n<p>有一个编译选项叫函数级别链接,可以使得某个函数或变量单独保存在一个段里面,都链接器需要用到某个函数时,就将它合并到输出文件中,对于没用到的函数则将他们抛弃,减少空间浪费,但这会减慢编译和链接过程,GCC编译器的编译选项是:</p>\n<pre><code class="lang-javascript">-ffunction-sections\n-fdata-sections\n</code></pre>\n<p>可能很多人都会以为程序都是由main函数开始执行和结束的,但其实不是,在main函数调用之前,为了保证程序可以顺利进行,要先初始化进程执行环境,如堆分配初始化、线程子系统等,C++的全局对象构造函数也是这一时期被执行的,全局析构函数是main之后执行的。</p>\n<p>Linux一般程序的入口是__start函数,有两个段:</p>\n<p>.init段:进程的初始化代码,一个程序开始运行时,在main函数调用之前,会先运行.init段中的代码。\n.fini段:进程终止代码,当main函数正常退出后,glibc会安排执行该段代码。</p>\n<p><strong>如何指定程序入口</strong></p>\n<p>在ld链接过程中使用-e参数可以指定程序入口,由于一段简短的printf函数其实都依赖了好多个链接库,我们也不太方便使用链接脚本将目标文件与所有这些依赖库进行链接,所以使用下面这段内嵌汇编的程序来打印一段字符串,这段程序不依赖任何链接库就可以打印出字符串内容,读者如果不懂其中的含义也不用担心,只需要了解下面介绍的链接知识就好。</p>\n<pre><code class="lang-javascript">const char* str = "hello";\n\nvoid print() {\n asm("movl $13,%%edx \\n\\t"\n "movl str,%%ecx \\n\\t"\n "movl $0,%%ebx \\n\\t"\n "movl $4,%%eax \\n\\t"\n "int $0x80 \\n\\t"\n :\n :"r"(str):"edx", "ecx", "ebx");\n}\n\n\nvoid exit() {\n asm("movl $42,%ebx \\n\\t"\n "movl $1,%eax \\n\\t"\n "int $0x80 \\n\\t");\n}\n\nvoid nomain() {\n print();\n exit();\n}\n</code></pre>\n<p>使用如下命令生成目标文件:</p>\n<pre><code class="lang-javascript">gcc -c -fno-builtin test.cc\n</code></pre>\n<p>看下输出的test.o的符号:</p>\n<pre><code class="lang-javascript">~/test$ nm -a test.o\n0000000000000000 b .bss\n0000000000000000 n .comment\n0000000000000000 d .data\n0000000000000000 d .data.rel.local\n0000000000000000 r .eh_frame\n0000000000000000 n .note.GNU-stack\n0000000000000000 r .rodata\n0000000000000000 t .text\n0000000000000026 T _Z4exitv\n0000000000000000 T _Z5printv\n0000000000000039 T _Z6nomainv\n0000000000000000 D str\n0000000000000000 a test.cc\n</code></pre>\n<p>这里由于我的源文件是.cc结尾,所以是以c++方式编译的,所以符号变成了上面的形式,如果变成了test.c,符号如下:</p>\n<pre><code class="lang-javascript">~/test$ gcc -c -fno-builtin test.c -o test.o\n~/test$ nm -a test.o\n0000000000000000 b .bss\n0000000000000000 n .comment\n0000000000000000 d .data\n0000000000000000 d .data.rel.local\n0000000000000000 r .eh_frame\n0000000000000000 n .note.GNU-stack\n0000000000000000 r .rodata\n0000000000000000 t .text\n0000000000000026 T exit\n0000000000000039 T nomain\n0000000000000000 T print\n0000000000000000 D str\n0000000000000000 a test.c\n</code></pre>\n<p>再使用-e指定入口函数符号:</p>\n<pre><code class="lang-javascript">~/test$ ld -static -e nomain -o test test.o\n~/test$ ./test\nhello\n</code></pre>\n', '程序一定要从main函数开始运行吗?本文涉及静态链接相关知识。\n\n对于静态链接先提出两个问题:\n\nQ:每个目标文件都有好多个段,目标文件在被链接成可执行文件时,输入目标文件中的各个段如何被合并到输出文件?\n\nA:合并相似的段,将所有的.text段合并到输出文件的.text段,将所有的.data段合并到输出文件的.data段。\n\nQ:链接器如何为他们分配在输出文件中的空间和地址?\n\nA:这里涉及到程序链接的两个步骤:\n\n空间与地址分配:扫描所有的输入目标文件,获得它们每个段的长度属性和位置,收集输入目标文件中的符号表中的所有符号定义和符号引用,统一放到一个全局符号表中,合并所有的段,计算出输出文件中各个段合并后的长度和位置,并建立映射关系。\n符号解析与重定位:使用第一步收集到的所有信息,读取输入文件中段的数据及重定位信息,进行符号解析和重定位,调整代码中的地址,将每个段中需要重定位的指令和数据进行“修补”,使他们都指向正确的位置。\ntips:外部符号指的是目标文件需要引用的符号,但是定义在其它目标文件中,链接前外部符号地址都是000000之类,链接后的可执行文件就可以看见这些外部符号都是有地址的。链接就是把相似的段放在一起,先找到段的偏移地址,再找出符号在段中的偏移,这样可以确定符号在整个可执行程序中的地址。\n\n对于那些需要重定位的符号,都会放在重定位表里,也叫重定位段,即.rel.data、.rel.text等,如果.text段有被重定位的地方,就有.rel.text段,如果.data段有被重定位的地方,就有.rel.data段。可以使用objdump查看目标文件的重定位表。\n\n**源代码:**\n\n\n\n```javascript\nint main() {\n printf("程序喵\\n");\n return 0;\n}\ngcc -c test\nobjdump -r test.o\n\ntest.o: file format elf64-x86-64\n\nRELOCATION RECORDS FOR [.text]:\nOFFSET TYPE VALUE\n0000000000000007 R_X86_64_PC32 .rodata-0x0000000000000004\n000000000000000c R_X86_64_PLT32 puts-0x0000000000000004\n\n\nRELOCATION RECORDS FOR [.eh_frame]:\nOFFSET TYPE VALUE\n0000000000000020 R_X86_64_PC32 .text\n```\n\n使用nm也可以查看需要重定位的符号:\n\n\n\n```javascript\nnm -u test.o\n U _GLOBAL_OFFSET_TABLE_\n U puts\n```\n对于UND类型,这种未定义的符号都是因为该目标文件中有关于他们的重定位项,在链接器扫描完所有的输入目标文件后,所有这种未定义的符号都应该能在全局符号表中找到,否则报符号未定义错误。\n\n注意:我们代码里明明用的是printf,为什么它却引用了puts的符号呢,因为编译器默认情况下会把只用一个字符串参数的printf替换成puts, 可以节省格式解析的时间,使用-fno-builtin会关闭这个内置函数优化选项,如下:\n\n\n\n```javascript\n~/test$ gcc -c -fno-builtin testlink.cc -o test.o\n~/test$ nm test.o\n U _GLOBAL_OFFSET_TABLE_\n0000000000000000 T main\n U printf\n```\n\ntips:现在的程序和库通常来讲都很大,一个目标文件可能包含成百上千个函数或变量,当需要用到某个目标文件的任意一个函数或变量时,就需要把它整个目标文件都链接进来,也就是说那些没有用到的函数也会被链接进去,这会导致链接输出文件变的很大,造成空间浪费。\n\n有一个编译选项叫函数级别链接,可以使得某个函数或变量单独保存在一个段里面,都链接器需要用到某个函数时,就将它合并到输出文件中,对于没用到的函数则将他们抛弃,减少空间浪费,但这会减慢编译和链接过程,GCC编译器的编译选项是:\n\n\n\n```javascript\n-ffunction-sections\n-fdata-sections\n```\n可能很多人都会以为程序都是由main函数开始执行和结束的,但其实不是,在main函数调用之前,为了保证程序可以顺利进行,要先初始化进程执行环境,如堆分配初始化、线程子系统等,C++的全局对象构造函数也是这一时期被执行的,全局析构函数是main之后执行的。\n\nLinux一般程序的入口是__start函数,有两个段:\n\n.init段:进程的初始化代码,一个程序开始运行时,在main函数调用之前,会先运行.init段中的代码。\n.fini段:进程终止代码,当main函数正常退出后,glibc会安排执行该段代码。\n\n**如何指定程序入口**\n\n在ld链接过程中使用-e参数可以指定程序入口,由于一段简短的printf函数其实都依赖了好多个链接库,我们也不太方便使用链接脚本将目标文件与所有这些依赖库进行链接,所以使用下面这段内嵌汇编的程序来打印一段字符串,这段程序不依赖任何链接库就可以打印出字符串内容,读者如果不懂其中的含义也不用担心,只需要了解下面介绍的链接知识就好。\n\n\n\n```javascript\nconst char* str = "hello";\n\nvoid print() {\n asm("movl $13,%%edx \\n\\t"\n "movl str,%%ecx \\n\\t"\n "movl $0,%%ebx \\n\\t"\n "movl $4,%%eax \\n\\t"\n "int $0x80 \\n\\t"\n :\n :"r"(str):"edx", "ecx", "ebx");\n}\n\n\nvoid exit() {\n asm("movl $42,%ebx \\n\\t"\n "movl $1,%eax \\n\\t"\n "int $0x80 \\n\\t");\n}\n\nvoid nomain() {\n print();\n exit();\n}\n\n```\n使用如下命令生成目标文件:\n\n\n\n```javascript\ngcc -c -fno-builtin test.cc\n```\n\n看下输出的test.o的符号:\n\n\n\n```javascript\n~/test$ nm -a test.o\n0000000000000000 b .bss\n0000000000000000 n .comment\n0000000000000000 d .data\n0000000000000000 d .data.rel.local\n0000000000000000 r .eh_frame\n0000000000000000 n .note.GNU-stack\n0000000000000000 r .rodata\n0000000000000000 t .text\n0000000000000026 T _Z4exitv\n0000000000000000 T _Z5printv\n0000000000000039 T _Z6nomainv\n0000000000000000 D str\n0000000000000000 a test.cc\n```\n\n这里由于我的源文件是.cc结尾,所以是以c++方式编译的,所以符号变成了上面的形式,如果变成了test.c,符号如下:\n\n\n\n```javascript\n~/test$ gcc -c -fno-builtin test.c -o test.o\n~/test$ nm -a test.o\n0000000000000000 b .bss\n0000000000000000 n .comment\n0000000000000000 d .data\n0000000000000000 d .data.rel.local\n0000000000000000 r .eh_frame\n0000000000000000 n .note.GNU-stack\n0000000000000000 r .rodata\n0000000000000000 t .text\n0000000000000026 T exit\n0000000000000039 T nomain\n0000000000000000 T print\n0000000000000000 D str\n0000000000000000 a test.c\n```\n\n再使用-e指定入口函数符号:\n\n\n\n```javascript\n~/test$ ld -static -e nomain -o test test.o\n~/test$ ./test\nhello\n```', NULL, NULL, '2020-06-08 14:02:50', 0, 2),
('d6e52a17d0f64a12926c5d885a2aaf82', 1000002, 'C中的冒牌货yiy', 'C++ const', '<h1 id="asdasd">asdasd</h1>\n<pre><code class="lang-javascript">#public class ma\n</code></pre>\n', '#asdasd\n\n\n```javascript\n#public class ma\n```', 'd6e52a17d0f64a12926c5d885a2aaf82', 'd6e52a17d0f64a12926c5d885a2aaf82.jpg', '2020-06-09 14:24:20', 2, 1),
('d8858a3530944188ae1a9384f6dd8a45', 1000002, '程序设计发展历程', '程序 发展 阶段 历程', '<p>一、前期\n二十世纪四十年代bai当计算机刚诞du生时,计算机需要程序员手动控制zhi。,德国工程dao师楚泽提出要用一种程序语言控制计算机。\n60年代末期为了应对软件危机,克服程序设计模型中都无法克服错误随着代码的扩大而扩大,这新的思考程序设计方式和程序设计模型——面向对象程序设计出现了。</p>\n<p>也就诞生了一批支持此技术的程序设计语言,比如eiffel,c++,java,这些语言都以新的观点去看待问题,即问题就是由各种不同属性的对象以及对象之间的消息传递构成。</p>\n<p>面向对象语言由此必须支持新的程序设计技术,例如:数据隐藏,数据抽象,用户定义类型,继承,多态等等。</p>\n<p>二、现状</p>\n<p>如今通用的编程语言有两种形式:汇编语言和高级语言。</p>\n<p>汇编语言和机器语言实质是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,容易识别和记忆。源程序经汇编生成的可执行文件不仅比较小,而且执行速度很快。</p>\n<p>高级语言是绝大多数编程者的选择。和汇编语言相比,它不但将许多相关的机器指令合成为单条指令,并且去掉了与具体操作有关但与完成工作无关的细节。\n三、趋势</p>\n<p>面向对象程序设计以及数据抽象在现代程序设计思想中占有很重要的地位,未来语言的发展将不在是一种单纯的语言标准,将会以一种完全面向对象,更易表达现实世界,更易为人编写。</p>\n<p>简单性:提供最基本的方法来完成指定的任务,只需理解一些基本的概念,就可以用它编写出适合于各种情况的应用程序。</p>\n<p>面向对象:提供简单的类机制以及动态的接口模型。对象中封装状态变量以及相应的方法,实现了模块化和信息隐藏;提供了一类对象的原型,并且通过继承机制,子类可以使用父类所提供的方法,实现了代码的复用。</p>\n<p>安全性:用于网络、分布环境下有安全机制保证。</p>\n<p>平台无关性:与平台无关的特性使程序可以方便地被移植到网络上的不同机器、不同平台。</p>\n<p>扩展资料:</p>\n<p>计算机语言的种类非常的多,总的来说可以分成机器语言,汇编语言,高级语言三大类。\n1、解释类:执行方式类似于我们日常生活中的“同声翻译”,应用程序源代码一边由相应语言的解释器“翻译”成目标代码(机器语言),一边执行,因此效率比较低,而且不能生成可独立执行的可执行文件,应用程序不能脱离其解释器,但这种方式比较灵活,可以动态地调整、修改应用程序。</p>\n<p>2、编译类:编译是指在应用源程序执行之前,就将程序源代码“翻译”成目标代码(机器语言),因此其目标程序可以脱离其语言环境独立执行,使用比较方便、效率较高。</p>\n<p>3、低级类:机器语言、汇编语言和符号语言。</p>\n<p>汇编语言:源程序必须经过汇编,生成目标文件,然后执行。</p>\n<p>机器语言:机器语言是指一台计算机全部的指令集合</p>\n<p>参考资料:百度百科-计算机语言</p>\n', '一、前期\n二十世纪四十年代bai当计算机刚诞du生时,计算机需要程序员手动控制zhi。,德国工程dao师楚泽提出要用一种程序语言控制计算机。\n60年代末期为了应对软件危机,克服程序设计模型中都无法克服错误随着代码的扩大而扩大,这新的思考程序设计方式和程序设计模型——面向对象程序设计出现了。\n\n也就诞生了一批支持此技术的程序设计语言,比如eiffel,c++,java,这些语言都以新的观点去看待问题,即问题就是由各种不同属性的对象以及对象之间的消息传递构成。\n\n面向对象语言由此必须支持新的程序设计技术,例如:数据隐藏,数据抽象,用户定义类型,继承,多态等等。\n\n二、现状\n\n如今通用的编程语言有两种形式:汇编语言和高级语言。\n\n汇编语言和机器语言实质是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,容易识别和记忆。源程序经汇编生成的可执行文件不仅比较小,而且执行速度很快。\n\n高级语言是绝大多数编程者的选择。和汇编语言相比,它不但将许多相关的机器指令合成为单条指令,并且去掉了与具体操作有关但与完成工作无关的细节。\n三、趋势\n\n面向对象程序设计以及数据抽象在现代程序设计思想中占有很重要的地位,未来语言的发展将不在是一种单纯的语言标准,将会以一种完全面向对象,更易表达现实世界,更易为人编写。\n\n简单性:提供最基本的方法来完成指定的任务,只需理解一些基本的概念,就可以用它编写出适合于各种情况的应用程序。\n\n面向对象:提供简单的类机制以及动态的接口模型。对象中封装状态变量以及相应的方法,实现了模块化和信息隐藏;提供了一类对象的原型,并且通过继承机制,子类可以使用父类所提供的方法,实现了代码的复用。\n\n安全性:用于网络、分布环境下有安全机制保证。\n\n平台无关性:与平台无关的特性使程序可以方便地被移植到网络上的不同机器、不同平台。\n\n扩展资料:\n\n计算机语言的种类非常的多,总的来说可以分成机器语言,汇编语言,高级语言三大类。\n1、解释类:执行方式类似于我们日常生活中的“同声翻译”,应用程序源代码一边由相应语言的解释器“翻译”成目标代码(机器语言),一边执行,因此效率比较低,而且不能生成可独立执行的可执行文件,应用程序不能脱离其解释器,但这种方式比较灵活,可以动态地调整、修改应用程序。\n\n2、编译类:编译是指在应用源程序执行之前,就将程序源代码“翻译”成目标代码(机器语言),因此其目标程序可以脱离其语言环境独立执行,使用比较方便、效率较高。\n\n3、低级类:机器语言、汇编语言和符号语言。\n\n汇编语言:源程序必须经过汇编,生成目标文件,然后执行。\n\n机器语言:机器语言是指一台计算机全部的指令集合\n\n参考资料:百度百科-计算机语言', 'd8858a3530944188ae1a9384f6dd8a45', 'd8858a3530944188ae1a9384f6dd8a45.png', '2020-06-08 14:06:32', 0, 1),
('de4521a9b1634763bcb17f366510d8a1', 1000000, 'C语言入门教程10集全', 'C 语言 入门', '<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n<h3 id="c-10-">C语言入门教程10集全</h3>\n', '###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全\n###C语言入门教程10集全', 'de4521a9b1634763bcb17f366510d8a1', 'de4521a9b1634763bcb17f366510d8a1.jpg', '2020-06-09 09:30:03', 0, 1),
('e0e7d463139948a4a63ebecaa8112710', 1000000, 'C++ Primer第四版中文版', 'C++ Primer 第四版 中文版 ', '<h2 id="-">内容简介 · · · · · ·</h2>\n<p>本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本版对前一版进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当前的业界最佳实践。书中不但新增大量教学辅助内容,用于强调重要的知识点,提醒常见的错误,推荐优秀的编程实践,给出使用提示,还包含大量来自实战的示例和习题。对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++初学者的最佳指南;对于中高级程序员,本书也是不可或缺的参考书。本书的前言阐述了 第4版和前一版的不同之处。</p>\n<h2 id="-">作者简介 · · · · · ·</h2>\n<p>本书所有作者都是著名的C++权威人物。</p>\n<p>Stanley B. Lippman目前是微软公司 Visual C++ 团队的架构师。他从1984年开始在贝尔实验室与C++的设计者Bjarne Stroustrup一起从事C++的设计与开发。他在迪士尼和梦工厂从事动画制作,还担任过JPL的高级顾问。他还著有Inside the C++ Object Model。</p>\n<p>Josée Lajoie曾经是IBM加拿大研究中心C/C++编译器开发团队的成员,在ISO C++标准委员会工作了7年,担任过ISO核心语言工作组的主席和C++ Report杂志的专栏作家。</p>\n<p>Barbara E. Moo是拥有25年软件经验的独立咨询顾问。在AT&T,她与Stroustrup、Lippman一起管理过复杂的C++开发项目。她和Andrew Koenig合著了Accelerated ...</p>\n<h2 id="-">目录 · · · · · ·</h2>\n<p>第1章 快速入门</p>\n<p>1.1 编写简单的C++程序</p>\n<p>1.2 初窥输入/输出</p>\n<p>1.3 关于注释</p>\n<p>1.4 控制结构</p>\n<p>1.5 类的简介</p>\n<p>1.6 C++程序</p>\n<p>小结</p>\n<p>术语</p>\n<p>第一部分 基本语言</p>\n<p>第2章 变量和基本类型</p>\n<p>2.1 基本内置类型</p>\n<p>2.2 字面值常量</p>\n<p>2.3 变量</p>\n<p>2.4 const限定符</p>\n<p>2.5 引用</p>\n<p>2.6 typedef名字</p>\n<p>2.7 枚举</p>\n<p>2.8 类类型</p>\n<p>2.9 编写自己的头文件</p>\n<p>小结</p>\n<p>术语</p>\n<p>第3章 标准库类型</p>\n<p>3.1 命名空间的using声明</p>\n<p>3.2 标准库string类型</p>\n<p>3.3 标准库vector类型</p>\n<p>3.4 迭代器简介</p>\n<p>3.5 标准库bitset类型</p>\n<p>小结</p>\n<p>术语</p>\n<p>第4章 数组和指针</p>\n<p>4.1 数组</p>\n<p>4.2 指针的引入</p>\n<p>4.3 C风格字符串</p>\n<p>4.4 多维数组</p>\n<p>小结</p>\n<p>术语</p>\n<p>第5章 表达式</p>\n<p>5.1 算术操作符</p>\n<p>5.2 关系操作符和逻辑操作符</p>\n<p>5.3 位操作符</p>\n<p>5.4 赋值操作符</p>\n<p>5.5 自增和自减操作符</p>\n<p>5.6 箭头操作符</p>\n<p>5.7 条件操作符</p>\n<p>5.8 sizeof操作符</p>\n<p>5.9 逗号操作符</p>\n<p>5.10 复合表达式的求值</p>\n<p>5.11 new和delete表达式</p>\n<p>5.12 类型转换</p>\n<p>小结</p>\n<p>术语</p>\n<p>第6章 语句</p>\n<p>6.1 简单语句</p>\n<p>6.2 声明语句</p>\n<p>6.3 复合语句(块)</p>\n<p>6.4 语句作用域</p>\n<p>6.5 if语句</p>\n<p>6.6 switch语句</p>\n<p>6.7 while语句</p>\n<p>6.8 for循环语句</p>\n<p>6.9 do while语句</p>\n<p>6.10 break语句</p>\n<p>6.11 continue语句</p>\n<p>6.12 goto语句</p>\n<p>6.13 try块和异常处理</p>\n<p>6.14 使用预处理器进行调试</p>\n<p>小结</p>\n<p>术语</p>\n<p>第7章 函数</p>\n<p>7.1 函数的定义</p>\n<p>7.2 参数传递</p>\n<p>7.3 return语句</p>\n<p>7.4 函数声明</p>\n<p>7.5 局部对象</p>\n<p>7.6 内联函数</p>\n<p>7.7 类的成员函数</p>\n<p>7.8 重载函数</p>\n<p>7.9 指向函数的指针</p>\n<p>小结</p>\n<p>术语</p>\n<p>第8章 标准IO库</p>\n<p>8.1 面向对象的标准库</p>\n<p>8.2 条件状态</p>\n<p>8.3 输出缓冲区的管理</p>\n<p>8.4 文件的输入和输出</p>\n<p>8.5 字符串流</p>\n<p>小结</p>\n<p>术语</p>\n<p>第二部分 容器和算法</p>\n<p>第9章 顺序容器</p>\n<p>第10章 关联容器</p>\n<p>第11章 泛型算法</p>\n<p>第三部分 类和数据抽象</p>\n<p>第12章 类</p>\n<p>第13章 复制控制</p>\n<p>第14章 重载操作符与转换</p>\n<p>第四部分 面向对象编程与泛型编程</p>\n<p>第15章 面向对象编程</p>\n<p>第16章 模板与泛型编程</p>\n<p>第五部分 高级主题</p>\n<p>第17章 用于大型程序的工具</p>\n<p>第18章 特殊工具与技术</p>\n<p>附录 标准库</p>\n<p>索引</p>\n', '##内容简介 · · · · · ·\n\n本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本版对前一版进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当前的业界最佳实践。书中不但新增大量教学辅助内容,用于强调重要的知识点,提醒常见的错误,推荐优秀的编程实践,给出使用提示,还包含大量来自实战的示例和习题。对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++初学者的最佳指南;对于中高级程序员,本书也是不可或缺的参考书。本书的前言阐述了 第4版和前一版的不同之处。\n\n##作者简介 · · · · · ·\n\n本书所有作者都是著名的C++权威人物。\n\nStanley B. Lippman目前是微软公司 Visual C++ 团队的架构师。他从1984年开始在贝尔实验室与C++的设计者Bjarne Stroustrup一起从事C++的设计与开发。他在迪士尼和梦工厂从事动画制作,还担任过JPL的高级顾问。他还著有Inside the C++ Object Model。\n\nJosée Lajoie曾经是IBM加拿大研究中心C/C++编译器开发团队的成员,在ISO C++标准委员会工作了7年,担任过ISO核心语言工作组的主席和C++ Report杂志的专栏作家。\n\nBarbara E. Moo是拥有25年软件经验的独立咨询顾问。在AT&T,她与Stroustrup、Lippman一起管理过复杂的C++开发项目。她和Andrew Koenig合著了Accelerated ...\n\n\n##目录 · · · · · ·\n第1章 快速入门\n\n1.1 编写简单的C++程序\n\n1.2 初窥输入/输出\n\n1.3 关于注释\n\n1.4 控制结构\n\n1.5 类的简介\n\n1.6 C++程序\n\n小结\n\n术语\n\n第一部分 基本语言\n\n第2章 变量和基本类型\n\n2.1 基本内置类型\n\n2.2 字面值常量\n\n2.3 变量\n\n2.4 const限定符\n\n2.5 引用\n\n2.6 typedef名字\n\n2.7 枚举\n\n2.8 类类型\n\n2.9 编写自己的头文件\n\n小结\n\n术语\n\n第3章 标准库类型\n\n3.1 命名空间的using声明\n\n3.2 标准库string类型\n\n3.3 标准库vector类型\n\n3.4 迭代器简介\n\n3.5 标准库bitset类型\n\n小结\n\n术语\n\n第4章 数组和指针\n\n4.1 数组\n\n4.2 指针的引入\n\n4.3 C风格字符串\n\n4.4 多维数组\n\n小结\n\n术语\n\n第5章 表达式\n\n5.1 算术操作符\n\n5.2 关系操作符和逻辑操作符\n\n5.3 位操作符\n\n5.4 赋值操作符\n\n5.5 自增和自减操作符\n\n5.6 箭头操作符\n\n5.7 条件操作符\n\n5.8 sizeof操作符\n\n5.9 逗号操作符\n\n5.10 复合表达式的求值\n\n5.11 new和delete表达式\n\n5.12 类型转换\n\n小结\n\n术语\n\n第6章 语句\n\n6.1 简单语句\n\n6.2 声明语句\n\n6.3 复合语句(块)\n\n6.4 语句作用域\n\n6.5 if语句\n\n6.6 switch语句\n\n6.7 while语句\n\n6.8 for循环语句\n\n6.9 do while语句\n\n6.10 break语句\n\n6.11 continue语句\n\n6.12 goto语句\n\n6.13 try块和异常处理\n\n6.14 使用预处理器进行调试\n\n小结\n\n术语\n\n第7章 函数\n\n7.1 函数的定义\n\n7.2 参数传递\n\n7.3 return语句\n\n7.4 函数声明\n\n7.5 局部对象\n\n7.6 内联函数\n\n7.7 类的成员函数\n\n7.8 重载函数\n\n7.9 指向函数的指针\n\n小结\n\n术语\n\n第8章 标准IO库\n\n8.1 面向对象的标准库\n\n8.2 条件状态\n\n8.3 输出缓冲区的管理\n\n8.4 文件的输入和输出\n\n8.5 字符串流\n\n小结\n\n术语\n\n第二部分 容器和算法\n\n第9章 顺序容器\n\n第10章 关联容器\n\n第11章 泛型算法\n\n第三部分 类和数据抽象\n\n第12章 类\n\n第13章 复制控制\n\n第14章 重载操作符与转换\n\n第四部分 面向对象编程与泛型编程\n\n第15章 面向对象编程\n\n第16章 模板与泛型编程\n\n第五部分 高级主题\n\n第17章 用于大型程序的工具\n\n第18章 特殊工具与技术\n\n附录 标准库\n\n索引\n', 'e0e7d463139948a4a63ebecaa8112710', 'e0e7d463139948a4a63ebecaa8112710.jpg', '2020-06-03 18:50:10', 0, 4),
('e782a32a2e744b68a2d46293036deb1a', 1000002, '二叉树的遍历算法', '算法 遍历 二叉树 C++', '<h2 id="-">题目要求</h2>\n<p>编写程序,用先序递归遍历法(或输入先序及中序递归遍历结点访问序列)建立二叉树的二叉链表存储结构,计算并输出二叉树的结点总数以及树的高度;然后输出其先序、中序、后序以及层次遍历结点访问次序。其中层次遍历的实现需使用循环队列。二叉树结点数据类型建议选用字符类型。</p>\n<h2 id="-">数据结构设计</h2>\n<p>采用C++的模板类,创建队列。每个队列对象中,elem指针用来建立长度为n的数组,n表示队列的容量,front表示队头指针,rear表示队尾指针,c表示队列中当前元素的个数。\n采用结构体建立二叉树,其中,data表示数据域,lchild表示左指针,rchild表示右指针,BiT表示二叉树结构体指针类型变量,BiTNode表示二叉树结构体类型变量。</p>\n<h2 id="-">算法设计简要描述</h2>\n<p>先序遍历建立二叉树:递归调用函数,不断读取字符,依次建立左子树和右子树,当读取到‘#’字符时,返回NULL指针,最终返回根结点指针。\n先序和中序遍历结点访问序列建立二叉树:\na. 先由先序序列求得根节点;\nb. 再由根节点在中序序列中的位置,知:它之前的访问的结点为其左子树结点,它之后访问的为其右子树结点;\nc. 递归应用a,b两条。</p>\n<pre><code class="lang-javascript">#include <conio.h>\n#include <iostream>\nusing namespace std;\ntypedef char ElemTp;\n#define MAX 20\ntemplate <typename T>\nclass Queue //模板类:队列\n{\npublic:\n Queue(); //默认构造函数\n Queue(int n); //构造函数,调用函数createQueue(int n),创建长度为n的队列\n ~Queue(); //虚构函数\n int createQueue(int n); //创建长度为n的队列\n int empty(); //判断队列是否为空\n int full(); //判断队列是否为满\n int enQueue(T e); //元素e入队\n int dlQueue(T &e); //元素出队,保存在e中\nprivate:\n T *elem; //建立长度为n的数组\n int n; //队列容量\n int front; //队头指针\n int rear; //队尾指针\n int c; //队列当前元素个数\n};\ntypedef struct node\n{\n ElemTp data; //数据域\n struct node *lchild, //左指针\n *rchild; //右指针\n}*BiT,BiTNode;\n\nvoid visit(BiT e) //访问函数 \n{\n if (e->data != NULL) //输出二叉树的数据域\n cout << e->data << " ";\n}\nvoid preorder(BiT bt) //先序遍历二叉树\n{\n if (bt)\n {\n visit(bt); //访问根节点\n preorder(bt->lchild); //递归调用遍历左子树\n preorder(bt->rchild); //递归调用遍历右子树\n }\n}\nvoid midorder(BiT bt) //中序遍历二叉树\n{\n if (bt)\n {\n midorder(bt->lchild); //递归调用遍历左子树\n visit(bt); //访问根节点\n midorder(bt->rchild); //递归调用遍历右子树\n }\n}\nvoid lasorder(BiT bt) //后序遍历二叉树\n{\n if (bt)\n {\n lasorder(bt->lchild); //递归调用遍历左子树\n lasorder(bt->rchild); //递归调用遍历右子树\n visit(bt); //访问根节点\n }\n}\nvoid layertravel(BiT bt) //层次遍历二叉树\n{\n if (bt == NULL)\n return;\n Queue<BiT> q(MAX); //建立队列\n q.enQueue(bt); //根节点入队\n while (!q.empty())\n {\n q.dlQueue(bt); //根节点出队\n visit(bt); //访问根节点\n if (bt->lchild)\n q.enQueue(bt->lchild); //左子树不空,访问左子树\n if (bt->rchild)\n q.enQueue(bt->rchild); //右子树不空,访问右子树\n }\n}\nBiT crtPreBT() //先序递归遍历建立二叉树算法\n{\n BiT bt;\n char ch;\n ch = getchar();\n if (ch == '#') //读到‘#’返回NULL指针\n return NULL;\n bt = new BiTNode(); //建立新的二叉树结点\n bt->data = ch;\n bt->lchild = crtPreBT(); //递归建立左子树\n bt->rchild = crtPreBT(); //递归建立右子树\n return bt;\n}\nBiT crtPreMidBT(char *pr, int &i, char *mi, int u, int v) //先序及中序递归遍历结点访问序列建立二叉树算法\n{\n BiT bt;\n int k;\n if (u > v)\n return NULL;\n bt = new BiTNode(); \n bt->data = pr[i++]; //pr[i]为子树根节点\n for (k = u; k <= v; k++) //mi[u...v]为子树中序序列\n {\n if (mi[k] == bt->data) //查找根节点在中序序列中的位置\n break;\n }\n bt->lchild = crtPreMidBT(pr, i, mi, u, k - 1); //递归建立左子树\n bt->rchild = crtPreMidBT(pr, i, mi, k + 1, v); //递归建立右子树\n return bt;\n}\nint height(BiT bt) //计算二叉树的高度\n{\n int hl, hr;\n if (!bt)\n return 0;\n hl = height(bt->lchild); //递归计算左子树的高度\n hr = height(bt->rchild); //递归计算右子树的高度\n return (hl > hr) ? (hl + 1) : (hr + 1); //返回整个二叉树的高度(左、右子树高度较大的值加一)\n}\nint nodeNum(BiT bt) //计算二叉树的总结点数\n{\n int nl, nr;\n if (!bt)\n return 0;\n nl = nodeNum(bt->lchild); //递归计算左子树的结点数 \n nr = nodeNum(bt->rchild); //递归计算右子树的结点数\n return nl + nr + 1; //返回整个二叉树的结点数(左、右子树结点数之和加一)\n}\nvoid choose(BiT &bt) //选择建立二叉树的方式\n{\n char num, pre[MAX], mid[MAX];\n int i = 0, u = 0, v;\n cout << "请选择建立二叉树的方式: " << endl;\n cout << "1. 先序遍历建立二叉树" << endl;\n cout << "2. 先序和中序遍历建立二叉树" << endl;\n num = _getch();\n switch (num)\n {\n case '1': //先序遍历建立二叉树\n {\n cout << "您选择了第一种方式." << endl;\n cout << "请输入先序遍历的字符序列: " << endl;\n bt = crtPreBT();\n } break;\n case '2': //先序和中序遍历建立二叉树\n {\n cout << "您选择了第二种方式." << endl;\n cout << "请输入先序遍历的字符序列: " << endl;\n cin.getline(pre, MAX);\n cout << "请输入中序遍历的字符序列: " << endl;\n cin.getline(mid, MAX);\n v = strlen(mid) - 1;\n bt = crtPreMidBT(pre, i, mid, u, v);\n } break;\n }\n}\ntemplate<typename T>\nQueue<T>::Queue() \n{\n front = rear = -1;\n c = 0;\n}\ntemplate<typename T>\nQueue<T>::Queue(int n) \n{\n createQueue(n);\n}\ntemplate<typename T>\nQueue<T>::~Queue()\n{\n c = 0;\n front = rear = -1;\n delete[]elem;\n}\ntemplate<typename T>\nint Queue<T>::createQueue(int n)\n{\n if (n <= 0)\n return 0;\n this->n = n;\n c = 0;\n front = rear = -1;\n elem = new T[n];\n if (!elem)\n return 0;\n return 1;\n}\ntemplate<typename T>\nint Queue<T>::empty()\n{\n return c == 0;\n}\ntemplate<typename T>\nint Queue<T>::full()\n{\n return c == n;\n}\ntemplate<typename T>\nint Queue<T>::enQueue(T e)\n{\n if (c == n)\n return 0; //队满,入队失败\n rear = (rear + 1) % n;\n elem[rear] = e;\n c++;\n return 1; //入队成功返回1\n}\ntemplate<typename T>\nint Queue<T>::dlQueue(T & e)\n{\n if (c == 0)\n return 0; //队空,出队失败\n front = (front + 1) % n;\n e = elem[front];\n c--;\n return 1; //出队成功返回1\n}\nint main()\n{\n</code></pre>\n<p><strong>程序输入:</strong></p>\n<p>先序序列:abc##de#g##f###</p>\n<p><strong>程序输出:</strong></p>\n<p>二叉树的高度是:5</p>\n<p>二叉树的总结点数是:7</p>\n<p>先序遍历:a b c d e g f</p>\n<p>中序遍历:c b e g d f a</p>\n<p>后序遍历:c g e f d b a</p>\n<p>层次遍历:a b c d e f g</p>\n', '##题目要求\n编写程序,用先序递归遍历法(或输入先序及中序递归遍历结点访问序列)建立二叉树的二叉链表存储结构,计算并输出二叉树的结点总数以及树的高度;然后输出其先序、中序、后序以及层次遍历结点访问次序。其中层次遍历的实现需使用循环队列。二叉树结点数据类型建议选用字符类型。\n##数据结构设计\n采用C++的模板类,创建队列。每个队列对象中,elem指针用来建立长度为n的数组,n表示队列的容量,front表示队头指针,rear表示队尾指针,c表示队列中当前元素的个数。\n采用结构体建立二叉树,其中,data表示数据域,lchild表示左指针,rchild表示右指针,BiT表示二叉树结构体指针类型变量,BiTNode表示二叉树结构体类型变量。\n##算法设计简要描述\n先序遍历建立二叉树:递归调用函数,不断读取字符,依次建立左子树和右子树,当读取到‘#’字符时,返回NULL指针,最终返回根结点指针。\n先序和中序遍历结点访问序列建立二叉树:\na. 先由先序序列求得根节点;\nb. 再由根节点在中序序列中的位置,知:它之前的访问的结点为其左子树结点,它之后访问的为其右子树结点;\nc. 递归应用a,b两条。\n\n\n\n```javascript\n#include <conio.h>\n#include <iostream>\nusing namespace std;\ntypedef char ElemTp;\n#define MAX 20\ntemplate <typename T>\nclass Queue //模板类:队列\n{\npublic:\n Queue(); //默认构造函数\n Queue(int n); //构造函数,调用函数createQueue(int n),创建长度为n的队列\n ~Queue(); //虚构函数\n int createQueue(int n); //创建长度为n的队列\n int empty(); //判断队列是否为空\n int full(); //判断队列是否为满\n int enQueue(T e); //元素e入队\n int dlQueue(T &e); //元素出队,保存在e中\nprivate:\n T *elem; //建立长度为n的数组\n int n; //队列容量\n int front; //队头指针\n int rear; //队尾指针\n int c; //队列当前元素个数\n};\ntypedef struct node\n{\n ElemTp data; //数据域\n struct node *lchild, //左指针\n *rchild; //右指针\n}*BiT,BiTNode;\n \nvoid visit(BiT e) //访问函数 \n{\n if (e->data != NULL) //输出二叉树的数据域\n cout << e->data << " ";\n}\nvoid preorder(BiT bt) //先序遍历二叉树\n{\n if (bt)\n {\n visit(bt); //访问根节点\n preorder(bt->lchild); //递归调用遍历左子树\n preorder(bt->rchild); //递归调用遍历右子树\n }\n}\nvoid midorder(BiT bt) //中序遍历二叉树\n{\n if (bt)\n {\n midorder(bt->lchild); //递归调用遍历左子树\n visit(bt); //访问根节点\n midorder(bt->rchild); //递归调用遍历右子树\n }\n}\nvoid lasorder(BiT bt) //后序遍历二叉树\n{\n if (bt)\n {\n lasorder(bt->lchild); //递归调用遍历左子树\n lasorder(bt->rchild); //递归调用遍历右子树\n visit(bt); //访问根节点\n }\n}\nvoid layertravel(BiT bt) //层次遍历二叉树\n{\n if (bt == NULL)\n return;\n Queue<BiT> q(MAX); //建立队列\n q.enQueue(bt); //根节点入队\n while (!q.empty())\n {\n q.dlQueue(bt); //根节点出队\n visit(bt); //访问根节点\n if (bt->lchild)\n q.enQueue(bt->lchild); //左子树不空,访问左子树\n if (bt->rchild)\n q.enQueue(bt->rchild); //右子树不空,访问右子树\n }\n}\nBiT crtPreBT() //先序递归遍历建立二叉树算法\n{\n BiT bt;\n char ch;\n ch = getchar();\n if (ch == \'#\') //读到‘#’返回NULL指针\n return NULL;\n bt = new BiTNode(); //建立新的二叉树结点\n bt->data = ch;\n bt->lchild = crtPreBT(); //递归建立左子树\n bt->rchild = crtPreBT(); //递归建立右子树\n return bt;\n}\nBiT crtPreMidBT(char *pr, int &i, char *mi, int u, int v) //先序及中序递归遍历结点访问序列建立二叉树算法\n{\n BiT bt;\n int k;\n if (u > v)\n return NULL;\n bt = new BiTNode(); \n bt->data = pr[i++]; //pr[i]为子树根节点\n for (k = u; k <= v; k++) //mi[u...v]为子树中序序列\n {\n if (mi[k] == bt->data) //查找根节点在中序序列中的位置\n break;\n }\n bt->lchild = crtPreMidBT(pr, i, mi, u, k - 1); //递归建立左子树\n bt->rchild = crtPreMidBT(pr, i, mi, k + 1, v); //递归建立右子树\n return bt;\n}\nint height(BiT bt) //计算二叉树的高度\n{\n int hl, hr;\n if (!bt)\n return 0;\n hl = height(bt->lchild); //递归计算左子树的高度\n hr = height(bt->rchild); //递归计算右子树的高度\n return (hl > hr) ? (hl + 1) : (hr + 1); //返回整个二叉树的高度(左、右子树高度较大的值加一)\n}\nint nodeNum(BiT bt) //计算二叉树的总结点数\n{\n int nl, nr;\n if (!bt)\n return 0;\n nl = nodeNum(bt->lchild); //递归计算左子树的结点数 \n nr = nodeNum(bt->rchild); //递归计算右子树的结点数\n return nl + nr + 1; //返回整个二叉树的结点数(左、右子树结点数之和加一)\n}\nvoid choose(BiT &bt) //选择建立二叉树的方式\n{\n char num, pre[MAX], mid[MAX];\n int i = 0, u = 0, v;\n cout << "请选择建立二叉树的方式: " << endl;\n cout << "1. 先序遍历建立二叉树" << endl;\n cout << "2. 先序和中序遍历建立二叉树" << endl;\n num = _getch();\n switch (num)\n {\n case \'1\': //先序遍历建立二叉树\n {\n cout << "您选择了第一种方式." << endl;\n cout << "请输入先序遍历的字符序列: " << endl;\n bt = crtPreBT();\n } break;\n case \'2\': //先序和中序遍历建立二叉树\n {\n cout << "您选择了第二种方式." << endl;\n cout << "请输入先序遍历的字符序列: " << endl;\n cin.getline(pre, MAX);\n cout << "请输入中序遍历的字符序列: " << endl;\n cin.getline(mid, MAX);\n v = strlen(mid) - 1;\n bt = crtPreMidBT(pre, i, mid, u, v);\n } break;\n }\n}\ntemplate<typename T>\nQueue<T>::Queue() \n{\n front = rear = -1;\n c = 0;\n}\ntemplate<typename T>\nQueue<T>::Queue(int n) \n{\n createQueue(n);\n}\ntemplate<typename T>\nQueue<T>::~Queue()\n{\n c = 0;\n front = rear = -1;\n delete[]elem;\n}\ntemplate<typename T>\nint Queue<T>::createQueue(int n)\n{\n if (n <= 0)\n return 0;\n this->n = n;\n c = 0;\n front = rear = -1;\n elem = new T[n];\n if (!elem)\n return 0;\n return 1;\n}\ntemplate<typename T>\nint Queue<T>::empty()\n{\n return c == 0;\n}\ntemplate<typename T>\nint Queue<T>::full()\n{\n return c == n;\n}\ntemplate<typename T>\nint Queue<T>::enQueue(T e)\n{\n if (c == n)\n return 0; //队满,入队失败\n rear = (rear + 1) % n;\n elem[rear] = e;\n c++;\n return 1; //入队成功返回1\n}\ntemplate<typename T>\nint Queue<T>::dlQueue(T & e)\n{\n if (c == 0)\n return 0; //队空,出队失败\n front = (front + 1) % n;\n e = elem[front];\n c--;\n return 1; //出队成功返回1\n}\nint main()\n{\n```\n**程序输入:**\n\n先序序列:abc##de#g##f###\n\n**程序输出:**\n\n二叉树的高度是:5\n\n二叉树的总结点数是:7\n\n先序遍历:a b c d e g f\n\n中序遍历:c b e g d f a\n\n后序遍历:c g e f d b a\n\n层次遍历:a b c d e f g\n', NULL, NULL, '2020-06-08 13:55:49', 3, 2),
('e8e72807a6a240759dd644709cd4464a', 1000002, '什么叫面向对象?', '面向对象 OOP', '<h3 id="-">入门便是不识</h3>\n<p>从我们开始接触Java这门语言后,就有人告诉我们这是一个面向对象的语言。说的最多的是new个对象,其实并不知道什么是对象。以为对象就是一个class(类),并不觉得有什么特殊。直到很久之后,面试官问到什么是OOP,嘴巴都是一个大O,OOP?WTF?那人厌恶的说到就是面向对象编程。我说:Java就是面向对象,就是一切以对象为载体,去编程,去面对。面试官: go out ! now!</p>\n<p>滚回来的我赶紧看看什么是OOP,Object Oriented Programming,原来就是面向对象的编程啊,还有OOD(面向对象的设计),OOA(面向对象的分析)。那什么是面向对象呢?要想了解这个问题我们要先了解面向过程,这样对比我们就好理解了。</p>\n<p>很早很早以前的编程是面向过程的,比如实现一个算术运算1+1 = 2,通过这个简单的算法就可以解决问题。但是随着时代的进步,人们不满足现有的算法了,因为问题越来越复杂,不是1+1那么单纯了,比如一个班级的学生的数据分析,这样就有了对象这个概念,一切事物皆对象。将现实的事物抽象出来,注意抽象这个词是重点啊,把现实生活的事物以及关系,抽象成类,通过继承,实现,组合的方式把万事万物都给容纳了。实现了对现实世界的抽象和数学建模。这是一次飞跃性的进步。</p>\n<p>举个最简单点的例子来区分 面向过程和面向对象</p>\n<p>有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择</p>\n<p>1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。</p>\n<p>2、去饭店,张开嘴:老板!来一份鱼香肉丝!</p>\n<p>看出来区别了吗?这就是1是面向过程,2是面向对象。</p>\n<p>面向对象有什么优势呢?首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃洛阳白菜,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成洛阳白菜吧,提高了可维护性。总的来说就是降低耦合,提高维护性!</p>\n<p>面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。</p>\n<p>面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。</p>\n<p>面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们我们使用的就是面向对象了。</p>\n<p>面向过程:</p>\n<p>优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。\n缺点:不易维护、不易复用、不易扩展.</p>\n<p>优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 .\n缺点:性能比面向过程差</p>\n<h3 id="-">原来君如此</h3>\n<p>面向对象的三大特性:\n1、封装\n隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。\n2、继承\n提高代码复用性;继承是多态的前提。\n3、多态\n父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。</p>\n<h3 id="-">五大基本原则:</h3>\n<p>1、单一职责原则SRP(Single Responsibility Principle)\n类的功能要单一,不能包罗万象,跟杂货铺似的。\n2、开放封闭原则OCP(Open-Close Principle)\n一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。\n3、里式替换原则LSP(the Liskov Substitution Principle LSP)\n子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~\n4、依赖倒置原则DIP(the Dependency Inversion Principle DIP)\n高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的是抽象的中国人,而不是你是xx村的。\n5、接口分离原则ISP(the Interface Segregation Principle ISP)\n设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。</p>\n', '###入门便是不识\n\n从我们开始接触Java这门语言后,就有人告诉我们这是一个面向对象的语言。说的最多的是new个对象,其实并不知道什么是对象。以为对象就是一个class(类),并不觉得有什么特殊。直到很久之后,面试官问到什么是OOP,嘴巴都是一个大O,OOP?WTF?那人厌恶的说到就是面向对象编程。我说:Java就是面向对象,就是一切以对象为载体,去编程,去面对。面试官: go out ! now!\n\n\n滚回来的我赶紧看看什么是OOP,Object Oriented Programming,原来就是面向对象的编程啊,还有OOD(面向对象的设计),OOA(面向对象的分析)。那什么是面向对象呢?要想了解这个问题我们要先了解面向过程,这样对比我们就好理解了。\n\n很早很早以前的编程是面向过程的,比如实现一个算术运算1+1 = 2,通过这个简单的算法就可以解决问题。但是随着时代的进步,人们不满足现有的算法了,因为问题越来越复杂,不是1+1那么单纯了,比如一个班级的学生的数据分析,这样就有了对象这个概念,一切事物皆对象。将现实的事物抽象出来,注意抽象这个词是重点啊,把现实生活的事物以及关系,抽象成类,通过继承,实现,组合的方式把万事万物都给容纳了。实现了对现实世界的抽象和数学建模。这是一次飞跃性的进步。\n\n\n举个最简单点的例子来区分 面向过程和面向对象\n\n有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择\n\n1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。\n\n2、去饭店,张开嘴:老板!来一份鱼香肉丝!\n\n看出来区别了吗?这就是1是面向过程,2是面向对象。\n\n面向对象有什么优势呢?首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃洛阳白菜,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成洛阳白菜吧,提高了可维护性。总的来说就是降低耦合,提高维护性!\n\n面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。\n\n面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。\n\n面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们我们使用的就是面向对象了。\n\n面向过程:\n\n优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。\n缺点:不易维护、不易复用、不易扩展.\n\n优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 .\n缺点:性能比面向过程差\n\n###原来君如此\n\n面向对象的三大特性:\n1、封装\n隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。\n2、继承\n提高代码复用性;继承是多态的前提。\n3、多态\n父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。\n\n###五大基本原则:\n\n1、单一职责原则SRP(Single Responsibility Principle)\n类的功能要单一,不能包罗万象,跟杂货铺似的。\n2、开放封闭原则OCP(Open-Close Principle)\n一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。\n3、里式替换原则LSP(the Liskov Substitution Principle LSP)\n子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~\n4、依赖倒置原则DIP(the Dependency Inversion Principle DIP)\n高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的是抽象的中国人,而不是你是xx村的。\n5、接口分离原则ISP(the Interface Segregation Principle ISP)\n设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。\n\n\n', 'e8e72807a6a240759dd644709cd4464a', 'e8e72807a6a240759dd644709cd4464a.jpg', '2020-06-08 14:15:45', 0, 1),
('f1dbb40d7c5948dbaf97184138c31f18', 1000000, 'C和指针.PDF', 'C 指针 PDF', '<p>《C和指针》图书目录</p>\n<p>第1章 快速上手</p>\n<p>1.1 简介</p>\n<p>1.1.1 空白和注释</p>\n<p>1.1.2 预处理指令</p>\n<p>1.1.3 main函数</p>\n<p>1.1.4 read_column_numbers函数</p>\n<p>1.1.5 rearrange函数</p>\n<p>1.2 补充说明</p>\n<p>1.3 编译</p>\n<p>1.4 总结</p>\n<p>1.5 警告的总结</p>\n<p>1.6 编程提示的总结</p>\n<p>1.7 问题</p>\n<p>1.8 编程练习</p>\n<p>第2章 基本概念</p>\n<p>2.1 环境</p>\n<p>2.1.1 翻译</p>\n<p>2.1.2 执行</p>\n<p>2.2 词法规则</p>\n<p>2.2.1 字符</p>\n<p>2.2.2 注释</p>\n<p>2.2.3 自由形式的源代码</p>\n<p>2.2.4 标识符</p>\n<p>2.2.5 程序的形式</p>\n<p>2.3 程序风格</p>\n<p>2.4 总结</p>\n<p>2.5 警告的总结</p>\n<p>2.6 编程提示的总结</p>\n<p>2.7 问题</p>\n<p>2.8 编程练习</p>\n<p>第3章 数据</p>\n<p>第4章 语句</p>\n<p>第5章 操作符和表达式</p>\n<p>第6章 指针</p>\n<p>第7章 函数</p>\n<p>第8章 数组</p>\n<p>第9章 字符串、字符和字节</p>\n<p>第10章 结构和联合</p>\n<p>第11章 动态内存分配</p>\n<p>第12章 使用结构和指针</p>\n<p>第13章 高级指针话题</p>\n<p>第14章 预处理器</p>\n<p>第15章 输入/输出函数</p>\n<p>第16章 标准函数库</p>\n<p>第17章 经典抽象数据类型</p>\n<p>第18章 运行时环境</p>\n<p>附录 部分问题答案</p>\n<p>下载 《C和指针》高清PDF电子书</p>\n<p>链接: <a href="https://pan.baidu.com/s/1csmEhQlUTxhbmAZsQUA4NA">https://pan.baidu.com/s/1csmEhQlUTxhbmAZsQUA4NA</a> 提取码: i4h9</p>\n', '《C和指针》图书目录\n\n第1章 快速上手\n\n1.1 简介\n\n1.1.1 空白和注释\n\n1.1.2 预处理指令\n\n1.1.3 main函数\n\n1.1.4 read_column_numbers函数\n\n1.1.5 rearrange函数\n\n1.2 补充说明\n\n1.3 编译\n\n1.4 总结\n\n1.5 警告的总结\n\n1.6 编程提示的总结\n\n1.7 问题\n\n1.8 编程练习\n\n第2章 基本概念\n\n2.1 环境\n\n2.1.1 翻译\n\n2.1.2 执行\n\n2.2 词法规则\n\n2.2.1 字符\n\n2.2.2 注释\n\n2.2.3 自由形式的源代码\n\n2.2.4 标识符\n\n2.2.5 程序的形式\n\n2.3 程序风格\n\n2.4 总结\n\n2.5 警告的总结\n\n2.6 编程提示的总结\n\n2.7 问题\n\n2.8 编程练习\n\n第3章 数据\n\n第4章 语句\n\n第5章 操作符和表达式\n\n第6章 指针\n\n第7章 函数\n\n第8章 数组\n\n第9章 字符串、字符和字节\n\n第10章 结构和联合\n\n第11章 动态内存分配\n\n第12章 使用结构和指针\n\n第13章 高级指针话题\n\n第14章 预处理器\n\n第15章 输入/输出函数\n\n第16章 标准函数库\n\n第17章 经典抽象数据类型\n\n第18章 运行时环境\n\n附录 部分问题答案\n\n下载 《C和指针》高清PDF电子书\n\n链接: https://pan.baidu.com/s/1csmEhQlUTxhbmAZsQUA4NA 提取码: i4h9', 'f1dbb40d7c5948dbaf97184138c31f18', 'f1dbb40d7c5948dbaf97184138c31f18.jpg', '2020-06-09 09:13:49', 0, 4),
('f988b26886e440a1a437d9fbb8705096', 1000002, 'C++ 多线程', '线程 pthread', '<h4 id="c-">C++ 多线程</h4>\n<p>多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。在一般情况下,有两种类型的多任务处理:基于进程和基于线程。</p>\n<p>基于进程的多任务处理处理的是程序的并发执行。基于线程的多任务处理的是同一程序的片段的并发执行。</p>\n<p>多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。</p>\n<p>C++ 不包含多线程应用程序的任何内置支持。相反,它完全依赖于操作系统来提供此功能。</p>\n<p>本教程假设您使用的是 Linux 操作系统,我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用,比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。</p>\n<h4 id="-">创建线程</h4>\n<p>有下面的例程,我们可以用它来创建一个 POSIX 线程:</p>\n<pre><code class="lang-javascript">#include <pthread.h>\npthread_create (thread, attr, start_routine, arg)\n</code></pre>\n<p>在这里,pthread_create 创建一个新的线程,并让它可执行。这个例程可在代码内的任何地方被调用任意次数。下面是关于参数的说明:</p>\n<table>\n<thead>\n<tr>\n<th style="text-align:left">参数</th>\n<th style="text-align:right">描述</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align:left">thread</td>\n<td style="text-align:right">一个不透明的、唯一的标识符,用来标识例程返回的新线程。</td>\n</tr>\n<tr>\n<td style="text-align:left">attr</td>\n<td style="text-align:right">一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。</td>\n</tr>\n<tr>\n<td style="text-align:left">start_routine</td>\n<td style="text-align:right">C++ 例程,一旦线程被创建就会执行。</td>\n</tr>\n<tr>\n<td style="text-align:left">arg</td>\n<td style="text-align:right">一个可能传递给 start_routine 的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。</td>\n</tr>\n</tbody>\n</table>\n<p>一个进程可以创建的最大线程数是依赖于实现的。线程一旦被创建,就是同等的,而且可以创建其他线程。线程之间没有隐含层次或依赖。</p>\n<h4 id="-">终止线程</h4>\n<p>有下面的例程,我们可以用它来终止一个 POSIX 线程:</p>\n<pre><code class="lang-javascript">#include <pthread.h>\npthread_exit (status)\n</code></pre>\n<p>在这里,pthread_exit 用于显式地退出一个线程。通常情况下,pthread_exit() 例程是在线程完成工作后无需继续存在时被调用。</p>\n<p>如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。</p>\n<h4 id="-">实例</h4>\n<p>这个简单的实例代码使用 pthread_create() 例程创建了 5 个线程。每个线程打印一个 "Hello World!" 消息,然后调用 pthread_exit() 终止线程。</p>\n<pre><code class="lang-javascript">#include <iostream>\n// 必须的头文件是\n#include <pthread.h>\n\nusing namespace std;\n\n#define NUM_THREADS 5\n\n// 线程的运行函数\nvoid* say_hello(void* args)\n{\n cout << "Hello w3cschool!" << endl;\n}\n\nint main()\n{\n // 定义线程的 id 变量,多个变量使用数组\n pthread_t tids[NUM_THREADS];\n for(int i = 0; i < NUM_THREADS; ++i)\n {\n //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数\n int ret = pthread_create(&tids[i], NULL, say_hello, NULL);\n if (ret != 0)\n {\n cout << "pthread_create error: error_code=" << ret << endl;\n }\n }\n //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;\n pthread_exit(NULL);\n}\n</code></pre>\n', '####C++ 多线程\n\n多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。在一般情况下,有两种类型的多任务处理:基于进程和基于线程。\n\n基于进程的多任务处理处理的是程序的并发执行。基于线程的多任务处理的是同一程序的片段的并发执行。\n\n多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。\n\nC++ 不包含多线程应用程序的任何内置支持。相反,它完全依赖于操作系统来提供此功能。\n\n本教程假设您使用的是 Linux 操作系统,我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用,比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。\n\n####创建线程\n有下面的例程,我们可以用它来创建一个 POSIX 线程:\n\n```javascript\n#include <pthread.h>\npthread_create (thread, attr, start_routine, arg) \n```\n\n在这里,pthread_create 创建一个新的线程,并让它可执行。这个例程可在代码内的任何地方被调用任意次数。下面是关于参数的说明:\n\n| 参数| 描述| \n| :-------- | --------:| \n| thread| 一个不透明的、唯一的标识符,用来标识例程返回的新线程。 | \n| attr| 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。 | \n| start_routine| C++ 例程,一旦线程被创建就会执行。 | \n| arg| 一个可能传递给 start_routine 的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。 | \n\n一个进程可以创建的最大线程数是依赖于实现的。线程一旦被创建,就是同等的,而且可以创建其他线程。线程之间没有隐含层次或依赖。\n\n####终止线程\n有下面的例程,我们可以用它来终止一个 POSIX 线程:\n\n\n\n```javascript\n#include <pthread.h>\npthread_exit (status) \n```\n\n在这里,pthread_exit 用于显式地退出一个线程。通常情况下,pthread_exit() 例程是在线程完成工作后无需继续存在时被调用。\n\n如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。\n\n####实例\n这个简单的实例代码使用 pthread_create() 例程创建了 5 个线程。每个线程打印一个 "Hello World!" 消息,然后调用 pthread_exit() 终止线程。\n\n\n\n```javascript\n#include <iostream>\n// 必须的头文件是\n#include <pthread.h>\n\nusing namespace std;\n\n#define NUM_THREADS 5\n\n// 线程的运行函数\nvoid* say_hello(void* args)\n{\n cout << "Hello w3cschool!" << endl;\n}\n\nint main()\n{\n // 定义线程的 id 变量,多个变量使用数组\n pthread_t tids[NUM_THREADS];\n for(int i = 0; i < NUM_THREADS; ++i)\n {\n //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数\n int ret = pthread_create(&tids[i], NULL, say_hello, NULL);\n if (ret != 0)\n {\n cout << "pthread_create error: error_code=" << ret << endl;\n }\n }\n //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;\n pthread_exit(NULL);\n}\n```', NULL, NULL, '2020-06-08 14:24:49', 1, 2);
/*!40000 ALTER TABLE `a_resources` ENABLE KEYS */;
-- 正在导出表 astringent.a_user 的数据:~3 rows (大约)
/*!40000 ALTER TABLE `a_user` DISABLE KEYS */;
INSERT INTO `a_user` (`USER_ID`, `USER_NAME`, `USER_EMAIL`, `USER_PASSWORD`, `USER_LEVEL`, `USER_DESCRIPTION`) VALUES
(1000000, '陆罡锋', '[email protected]', 'admin', 5, '欢迎使用C++课程资源共享网站。'),
(1000002, '程序羊', '[email protected]', '12345678', 1, '');
/*!40000 ALTER TABLE `a_user` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;