本博客为完成结对项目所需的先导知识,题目不难,请认真对待 :)html
欢迎来到软件工程 :)java
注:本次实验为附加做业,不作不扣分,作了有附加分c++
阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个做业:家长天天要给孩子出一些合理的,但要有些难度的四则运算题目,而且家长要对孩子的做业打分记录。git
做为程序员的阿超心想,既然天天都须要出题,那何不作一个能够自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就造成了这个软件的需求:程序员
n
道加减乘除(分别使用符号+-*/
来表示)练习题,每一个数字在 0
和 100
之间,运算符在 2
个 到 3
个之间。3÷5+2=2.6
这样的算式。n
道练习题及其对应的正确答案输出到一个文件 subject.txt
中。当程序接收的参数为4时,如下为一个输出文件示例。github
13+17-1=29 11*15-5=160 3+10+4-16=1 15÷5+3-2=4
此次阿超选择使用他最拿手的 C++
语言来完成这样的需求,工欲善其事必先利其器,第一步就须要先安装一个好用的 IDE ,在这里咱们推荐使用 Visual Studio 2017
。算法
Visual Studio 2017 有着宇宙最强 IDE 的美称,它对 C++ 的支持也很好,在本教程中,为简化学员的开发难度,咱们选择使用 VS2017 社区版(社区版(Community)指的是可免费提供给单个开发人员,给予初学者及大部分程序员支持,能够无任何经济负担、合法地使用的版本。)编程
下面提供三种安装方法:浏览器
下载迅雷,输入如下ed2k连接:服务器
ed2k://|file|mu_visual_studio_community_2017_version_15.3_x86_x64_11100062.exe|1069960|5984B3CD547F9F213DE21EFE5887F08D|/
百度网盘:连接: https://pan.baidu.com/s/1jJXyRMA 密码: ub6c
下载的文件只是一个引导安装程序,下载完成后,双击运行,若是出现下面的 Visual Studio 提示:
则须要首先自行安装版本较高的 .Net Framework
( .NET Framework 4.6 能够在这里下载到)若是没有出现该提示,请忽略。
在点击开 exe
文件后,一路继续,能够看到以下的选择界面。因为咱们只须要 C++
库,因此只须要勾选 【使用 C++
的桌面开发】便可。因为 VS
自己体积较大,推荐修改存储位置,将其安装在非系统盘目录。
若是顺利的话,过一大段时间 VS2017 就会下载好相应文件,此时会提示要求重启,此时按照指示重启便可。
安装成功后,首次使用 VS 2017 还须要对其进行简单的配置,包括开发环境的主题风格。若是要求登陆的话,可使用你的outlook帐号登陆,或者能够选择忽略。
这里开发设置选择 C++便可,主题推荐深色主题。
阿超的项目放在了当下最流行的源代码管理平台 Github
上,仓库地址。那么,咱们如何在阿超项目的基础上进行开发呢?
成功登陆后,输入阿超仓库的网址 https://github.com/ChildishChange/Calculator ,点击右上角的 Fork
,将阿超的四则运算库拷贝到本身的同名仓库中,以下图所示:
拷贝成功后,能够看到本身已经拥有了一个同名仓库。这里咱们登陆的是 buaase 的帐号:
在本身的电脑上安装 Git 软件,Git 的安装教程在这里。在本身拷贝项目的主页的绿色按钮处能够找到一个可克隆的项目地址,下面是一个示例:
在 个人电脑 中任意找一个目录,打开 Git 命令行软件(Windows上可在空白处右键打开 Git Bash ),输入 git clone <clone url>
,其中 <clone url>
即咱们刚刚复制的项目地址。一个动W态演示图以下所示(这里 https://github.com/buaase/Calculator.git 就是咱们 Fork 后仓库的地址):
在完成上述操做后,可在当前目录下看到一个与仓库同名的文件夹Calculator
,这就是克隆到本地的项目。注意,默认克隆的分支是 java,请使用 git checkout cplusplus 命令切换到 C++
项目。 进入项目文件夹,新建一个文件夹,重命名为你的 Github
帐号名。
以 Github 帐号命名的文件夹做为项目目录,打开 VS2017,点击左上角的 文件
-> 新建
-> 项目
,以下图所示,选择 Visual C++
中的 控制台应用程序
。注意更改 位置
参数到刚刚新建的文件夹所在的路径。好比个人帐户名为 buaase
,刚刚新建的文件夹路径为D:\Calculator\buaase
,解决方案的名称也能够是 Calculator
,自定义便可。
新建项目后会出现一些默认的 stdafx.cpp
与 .h
为后缀的头文件。找到与解决方案同名的 cpp
文件,好比解决方案为 ConsoleApplication1
,那么会有一个名叫 ConsoleApplication1.cpp
的文件。将 src
目录下 Calculator.cpp
文件的内容拷贝到该文件中。右键点击 头文件
,新建一个头文件,修更名称为 Calculator.h
,并将 src
目录下 Calculator.h
文件的内容拷贝到新的头文件中。此时,右键点击解决方案,选择 编译解决方案
,成功后点击 本地Windows调试器
便可运行,示意图以下:
接下来接连使用 git add,git commit -m "Message"
(Message是你要写的内容)便可利用 Git 记录下全部的改动。若是是初次使用 Git,请在使用上述两条命令前使用以下两条命令配置本身的我的邮箱与 Commit 时的用户名,这里的邮箱和用户名最好与 Github 帐号保持一致。
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com
下面是一些常见的Git操做,可留做备忘
$ git clone [url] 下载一个项目以及它全部的版本历史 $ git add [file] 将文件进行快照处理用于版本控制 $ git commit -m"[descriptive message]" 将文件快照永久地记录在版本历史中 $ git push 上传当前本地分支commit到GitHub上 $ git pull 下载服务器上最新的本部并合并更改到本地 $ git reset [commit hash] 撤销全部[commit hash]后的的commit,在本地保存更改 $ git log 列出当前分支的版本历史
对于Github平台有疑问的,能够在 http://github.com/help 找到解决方案。
要想在 VS2017 里对 C++ 项目进行单元测试,首先要新建一个测试项目。右键单击解决方案,能够添加一个新建项目,在类型里选择 单元测试
,咱们这里新建了一个名为 CalculatorUnitTest
的单元测试项目。
在项目建立成功后,为单元测试项目 CalculatorUnitTest
增长对原项目的引用,以实现调用原项目函数接口的功能。
光设置引用还不够,接下来让咱们手动设置一下测试项目的附加依赖项。选中单元测试项目,右键点击选择 属性
在打开的左侧菜单栏中选择 配置属性
-> 连接器
-> 输入
,在 附加依赖项
的下拉选择框中选择 <编辑...>
,将被测试项目产生的全部 obj 文件路径(注意:并不是每次单元测试都固定写 Calculator.obj ,它决定于 C++源文件的名字)写到附加依赖项中,以下图所示:
这两个obj 文件能够在以下图文件夹(Project/Debug/)中找到:
在完成单元测试的项目配置后,下面咱们就能够开始写单元测试代码了。首先看向新建立的单元测试项目,里面应该会有一个默认的 unittest1.cpp
文件,打开该文件,应该是长这样的:
#include "stdafx.h" #include "CppUnitTest.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace CalculatorUnitTest { TEST_CLASS(UnitTest1) { public: TEST_METHOD(TestMethod1) { //请输入测试代码 } }; }
为了能顺利引用刚刚写好的接口,咱们须要引入Calculator工程的接口定义头文件,即 calculator.h。在头文件部分插入一行
#include "../Calculator/calculator.h"
而后咱们就能够顺利引用相关接口了。经过阅读方法 Solve 的注释与代码,咱们不难发现,它的参数是字符串形式的四则运算表达式,返回的应该是该表达式的答案。如今咱们来填充第一个测试用例,TEST_METHOD 其实就是一个宏,后面跟着的 TestMethod1 才是单元测试真正的名字。在该方法中插入以下代码块:
Calculator* calc = new Calculator(); string ret = calc->Solve("11+22"); Assert::AreEqual(ret, (string)"11+22=33");
这里咱们用到了 Assert(断言)。编写单元测试时,咱们老是会作出一些假设,好比咱们指望一个函数在接受预期的输入后就返回预期的输出,断言就是用于在代码中捕捉这些假设。通常来讲,单元测试中都会有断言的存在,没有断言存在的单元测试实际上是“假大空”的,没有任何对程序输入输出的假设约束。
下面咱们来运行一下这个单元测试,看 Solve 函数是否符合咱们的指望。找到菜单栏中的 测试
,运行全部测试便可,以下图所示
在单元测试运行完毕后,VS 的左侧会弹出一个测试结果窗口。绿色表明经过,红色表明失败。从本次的结果来看,咱们经过了这个单元测试。
那么也就是说,当 solve 函数的输入为 "11+22"
时,其实际的输出就是 "11+22=33"
,与预期现象温和。固然,咱们这里只是经过了一个简单的测试用例,不能说这个函数就是必定正确的。因此咱们须要加一些单元测试,以验证在怎样的状况下这个函数可能会出错,如今请你帮助阿超补充一些针对 solve 方法的单元测试用例吧。
上面咱们学习了如何使用 IDE 进行单元测试,也测试出了 solve 方法的确有些问题。那么该如何定位问题所在呢?这就要用到 IDE 的调试功能了。下面咱们就来介绍一下 Visual Studio 的调试方法。
断点
调试程序首先要会设置断点和单步运行。在 VS 中设置断点很是简单,在要设置断点的行号旁用鼠标单击一下就好了(注意要点到与右侧编辑器颜色明显不一样的区域),以下图所示,咱们在第 31 行设了个断点:
单步运行
在设置好断点后,咱们就能够启动 Debug 模式。咱们这里因为默认启动项目是 Calculator ,因此直接点击以下所示的 本地 Windows 调试器
按钮便可开始调试。
若是一个解决方案中有多个Cpp项目,要首先指定启动项目。
启动调试后,这时能够看到程序已经运行到刚刚打的断点处前。下方的自动窗口能够看到各个变量的值。
与其余 IDE 相似,咱们也能够经过手动设置监视一些感兴趣的变量。点击选项卡到 监视 1
中,按照下图所示方式添加监视,可在界面中只显示监控变量的值。
此时咱们的第31行代码并无执行,下面咱们利用单步运行的方法执行该语句。单步运行有两种:Step Into(逐语句,快捷捷F11) 和 Step Over(逐过程,快捷捷F10),分别对应这两个图标。(这些图标都在刚才启动本地调试器按钮的旁边)
这两种单步运行功能在运行语句时没有区别,在执行方法调用语句时,Step Into 会跳入方法实现,Step Over 会直接执行完方法,实际使用中咱们优先使用 Step Over,只有方法执行出错了,说明程序问题在被调用方法中,这时再回来经过 Step Into 进入方法进行调试。咱们单击一下 Step Over 图标(或 F10 ),程序停在了第 33 行(向右的小黄箭头指示目前执行到第几行,也可使用这个图标表明的按钮 )
这时咱们能够看到执行了 31 行代码后 formulaChar 目前的值。
条件断点
有些状况下咱们只但愿断点在某些条件下才成立,该如何作呢?其实很是简单,右键单击红色的断点符号,便可弹出条件选项。
在这里咱们能够输入 Condition,设定为只有某些前置变量的值知足条件时咱们才会触发断点,帮助咱们高效率测试。好比咱们这里设定 Condition 为 j == 0
:
从下图中咱们能够看到当断点生效时,j 的值为 0。
咱们如今的程序中暗藏了两个BUG,一个是不符合题目的需求,另外一个是实现上有一个小问题。如今请你利用刚学习到的单元测试与 Debug 的相关知识,找出程序的 Bug 吧!
单元测试不只仅用来保证当前代码的正确性,更重要的是用来保证代码修复、改进或重构以后的正确性。也就是说,在每次修改完 Bug 以后,咱们其实都须要运行一遍来看看是否是知足以前全部的单元测试样例。因此,在每次由于现有的 failed test 而修复原有代码后,最好都所有运行一遍单元测试,保证之前 passed test 仍然是能够经过的。
一样地,Git 的使用也是讲究勤提交,提交的粒度最好是细到每一个小功能的完成。一个小功能能够是一处小 Bug 的修复,也能够是一个简单函数的实现。因此,在咱们本次的编程训练任务中,Git 至少会提交 2 次或以上。
为了测试并改进程序生成四则运算算式的效率,咱们须要使用效能分析工具。效能分析工具并不能帮助咱们直接改进算法的效率,但它能够帮咱们分析找到代码中执行效率最差,也就是所谓 效能瓶颈
的部分。这以后咱们就能够把精力花费在改进瓶颈上,从而高效快速地提高程序性能。
Visual Studio 内置了很是棒的效能工具,学名叫作 性能探查器
。点击 IDE 顶部菜单栏中的 分析
,便可看到 性能探查器
。
咱们这里关注在程序的执行效率方面,因此咱们选择测试 CPU 使用率
便可。若是想探查内存泄露问题,也能够选择使用其余选项。
先别急着开始探查。咱们的代码目前只产生 1 个四则运算算式,不存在性能问题。咱们首先来给代码多加几百万个循环,让它运行 足够长
时间,才能准确测出代码的效能问题。增长循环体后的 main 函数体以下所示
int main() { for (int i = 0; i < 10000000; i++) { Calculator* calc = new Calculator(); string question = calc->MakeFormula(); cout << question << endl; string ret = calc->Solve("11+22"); cout << ret << endl; } }
好了,如今让咱们开始效能分析。即便程序没有执行完成,效能分析也是能够强行结束的。让程序跑几十秒以后,就能够结束。点击效能分析工具界面左上角的 中止收集
便可中止收集数据。
下图就是一份完整的效能分析报告。
从图中咱们能够看到,Solve 方法在总 CPU 耗时中占了约 30% 左右,但若是想得到更详细的信息(好比具体到哪一行占了这么久,详细报告阅读起来更易懂),咱们须要点击上图中的 建立详细的报告...
,建立完成后会自动打开一个后缀为 .vspx
的文件,以下图所示:
咱们点进 Calculator::Solve 看看,能够看到很是清晰的每行代码占用 CPU 的时间比例,以下图左侧所示。而后咱们就能够着手改进代码的效率,好比结合场景用更高效的数据结构,优化一些没有用的代码等等。
在完成 Debug
与 单元测试
以后,咱们如今来学习一下如何提交代码到 Github 上,并利用 Github 进行团队协做。以前咱们已经介绍过了 git add
与 git commit
命令,但这两条命令只会对本地的仓库进行修改,也就是说以前的全部操做都是离线的。咱们要想让 Github 上也跟踪到最新的改变,就须要使用 git push
命令。
在使用该命令前,请确保全部本地的改动都已经 add
并 commit
了。能够用 git status
来检查:
出现如图所示的 nothing to commit
即说明已经能够 push 了。使用 push 命令后,会弹出一个窗口要求登陆 Github,此时输入 Github 的 用户名或邮箱
与 密码
便可成功 push。
成功的提示以下所示,其中 master 部分应该是 java / cplusplus。
在完成 push 后,咱们就能够开始向源仓库(即阿超的仓库)发起 Pull Request(简称 PR ,指发起请求给仓库贡献代码)。打开你 Fork 后的项目主页,如图所示,点击按钮 New pull request
若是你按照教程的节奏一步步走下来了,那么在点击 New Pull Request后,应该出现以下所示界面。若是不是,请联系群内的助教/老师,或者在本博客下留言补充错误截图。
此时点击 Create pull request
便可发起请求。等待仓库主人阿超经过审核后,你的代码就能够成功合并进阿超的仓库。至此就完成了整个教程,恭喜!