简介:C++实验指导书面向高校C++课程学习者与实验指导教师,围绕图书管理系统的设计与实现组织内容,采用任务分解方式串联开发环境与程序设计步骤、类和对象、类的派生、多态性与虚函数、输入输出流五个实验,帮助读者在动手实践中理解封装、继承与多态等面向对象理念。压缩包共1个doc文件,约965KB,内容含各实验的目的要求、设备分组、内容步骤与课后作业,并强调按附录格式撰写实验报告、准确记录数据与及时分析结果。已有287人学习。读者可据此安排自主训练或课堂实验,获得从基础语法到综合设计的完整实验线索,也可参考其任务拆分方法组织教学与课程作业。
1. 装环境不是走过场:VC++ 6.0 在今天的机器上到底怎么落地
很多人拿到这份 C++ 实验指导书,手指头先翻到实验二看类和对象,结果第一行就停住了,因为指导书里每个步骤都默认为你已经装好了 Visual C++ 6.0,也默认你会在 Developer Studio 里新建工程。真到动手安装这一步,才会发现这套环境装在新机器上并不省心:安装完成却打不开,打开后编译报错,Ctrl+F5 一运行窗口就消失,连实验一那个最简单的菜单程序都跑不起来,后面四个实验就全被卡住了。这份指导书本身是任务书,不是安装手册,环境这一层只能自己补上。下面按装什么、怎么装、装坏了怎么救的顺序,把 c++ 实验课程需要的那套开发环境一步步装起来,让这台机器能编译、能调试,也能写出符合附录格式的实验报告。
2. 装 VC++ 6.0:路径、组件与兼容性三个决定成败的选项
2.1 动手前先核对环境条件
指导书里写了三个设备条件:Windows 2000 以上操作系统、Visual C++ 6.0 语言环境、每人一台 PC 机。前两条放到今天需要翻译一下,因为 Windows 2000 已经是很早的系统了,而 VC++ 6.0 是 32 位程序,它在这十几年的 Windows 上能活,但需要额外配置。我一般的判断标准是这样的:
| 项目 | 指导书原文 | 今天实际怎么落 |
|---|---|---|
| 操作系统 | Windows 2000 以上 | Win7 / Win10 / Win11 都能跑,64 位系统也没问题,但必须开兼容模式 |
| IDE 主程序 | Visual C++ 6.0 | 主程序是 MSDEV.EXE,位于 Common\MSDev98\Bin 下 |
| 编译器 | 集成环境中 | 独立命令是 VC98\Bin 下的 cl.exe 与 link.exe |
| 磁盘空间 | 未写 | 完整安装约几百 MB,建议预留 1 GB 以上给后续工程的 Debug 输出 |
| 账号权限 | 未写 | 安装与首次运行都要管理员权限,否则注册表写不进去、调试器挂不上 |
| 安装路径 | 未写 | 不要带空格和中文,我固定用 C:\VC6 |
最后一行是重点。VC++ 6.0 这套工具链对含空格的路径处理得不好,默认安装会落到Program Files下面,编译时偶尔冒出LNK1104: cannot open file,查半天发现是路径里的空格被当成了参数分隔。安装到C:\VC6这种纯英文短路径下,能省掉一批找不出原因的失败。同理,工程目录也别放在桌面或者“新建文件夹”这种中文路径下,指导书里那个C:\DOCUMENTS AND SETTINGS\...\桌面\新建文件夹的例子是当年的写法,现在照着做,编译报错的概率会明显变高。
2.2 安装过程:选手动组件,别一路下一步
安装程序启动后会出现组件选择界面,默认是全部勾上。全部安装会带入一堆和本课程无关的组件,还会拖慢首次启动。按实验一到实验五的需求,只需要下面这几项:
- Visual C++ 6.0 本体,编译器、链接器、调试器、MFC 都在里面,这一项必选;
- Developer Studio 集成环境,也就是后面天天要开的那个窗口;
- 联机文档和示例代码可以不选,装了也只是占空间;
- 企业版工具里那些数据库、建模组件对五个实验没有帮助,取消掉。
安装类型选“自定义”,路径统一写成C:\VC6,其余保持默认。安装完成后别急着点开 IDE,先在命令行里确认三件事:编译器在不在、链接器在不在、IDE 主程序在不在。
:: 安装完成后先做一次目录自检,三个都返回文件信息才算装完整 dir C:\VC6\VC98\Bin\cl.exe dir C:\VC6\VC98\Bin\link.exe dir C:\VC6\Common\MSDev98\Bin\MSDEV.EXE这三条命令分别对应编译阶段、连接阶段和图形界面。任意一条报“找不到文件”,说明安装时漏勾了组件,需要重新跑一遍安装程序补装,而不是在后面的编译错误里死磕。很多“装完不能用”的现场,问题就出在这里:IDE 装上了,编译器没装,界面能打开,一编译就报找不到 cl.exe。
2.3 首次启动前的兼容性设置
这是整套环境里最容易省略、也最能决定后续体验的一步。VC++ 6.0 的主程序在新系统上直接双击,常见结果是闪退、界面残缺,或者“打开文件”对话框卡死几秒后消失。我一般在第一次启动前就把兼容性设好,一次设置之后就好用了:
找到C:\VC6\Common\MSDev98\Bin\MSDEV.EXE,右键属性,在“兼容性”标签里做三件事:勾选以兼容模式运行,模式选 Windows XP (Service Pack 3);勾选以管理员身份运行此程序;勾选禁用视觉主题。前两项解决启动和注册表写入的问题,第三项解决菜单和工具栏绘制异常的问题。如果显示器是高分屏,还需要在“更改高 DPI 设置”里把缩放行为改成“应用程序”,否则 IDE 界面会被系统拉伸得很糊,代码字体看起来发虚。
设置完之后建一个桌面快捷方式,以后统一从这个快捷方式进。这一步最好一次做完,因为兼容性设置是跟着 exe 走的,换个快捷方式不会丢,但如果直接双击MSDEV.EXE和双击设过兼容性的快捷方式,行为可能不一样,一旦习惯混着用,出问题时很难判断是哪条路径进来的。
2.4 环境变量与命令行验证
图形界面能打开,不代表工具链就是通的。先把编译相关的路径写进系统环境变量,后面无论是用 IDE 还是直接在命令行编译,都能少一层排查:
:: 系统环境变量里追加,PATH 让 cl/link 能被直接调用 set PATH=C:\VC6\VC98\Bin;C:\VC6\Common\MSDev98\Bin;%PATH% set INCLUDE=C:\VC6\VC98\Include set LIB=C:\VC6\VC98\LibPATH决定命令行敲cl时能不能找到编译器,INCLUDE指向标准头文件目录,LIB指向静态库目录。这三条如果缺了INCLUDE,编译时会报fatal error C1083: Cannot open include file: 'iostream.h',很多人以为是代码写错,其实是头文件搜索路径没配。写完环境变量要新开一个命令行窗口才生效,旧窗口读的还是旧值。
配完立刻验证,别等到写代码时才发现工具链是坏的。建一个最小文件:
// toolcheck.cpp —— 只为验证工具链,不进入任何实验工程 #include <iostream.h> int main() { cout << "toolchain ok" << endl; // 能打印出来说明编译、链接、运行全通 return 0; }cd /d C:\cpplab\toolcheck cl toolcheck.cpp toolcheck.execl一次完成编译和链接,生成.obj与.exe,然后直接执行 exe。屏幕上出现toolchain ok,说明第 2 章这套环境已经落地,可以进实验一了。这一步看着多余,但它把“IDE 能不能开”和“编译器能不能用”这两件事拆开了,后面出问题能立刻判断是哪一层坏了。
3. 第一个工程:从新建项目到 Ctrl+F5 跑通实验一
3.1 建一个 Win32 Console Application 空工程
实验一的核心是让你走完“分析、编辑、编译、连接、运行”这条链路,所以第一个工程必须按指导书的路径建,不能图省事直接新建一个 .cpp 文件编译。指导书写得清楚:选择 File 菜单的 New,切到 Projects 标签,类型选Win32 Console Application,表示要生成一个 Windows 32 位控制台应用程序,Location 填工程所在目录,Project Name 填工程名,比如Exe1_1。
工程向导那一步要选An empty project,不要选带示例代码的模板。空工程的意思是不预置任何源文件,后面自己建.cpp加进去。选模板会生成一堆用不到的文件,第一次做实验的人容易分不清哪些是自己写的、哪些是系统给的,交实验报告时源文件清单也会写乱。
工程建好后,目录里会多出.dsp和.dsw两个文件。.dsw是工作区文件,.dsp是项目文件,双击.dsw就能把整个工程打开。这两个文件必须和源文件一起留着,删了源文件还能重写,删了.dsw就得重新建工程。
3.2 把 .cpp 加进项目:Add to project 那个勾一定要打上
第二步是建源文件。File 菜单再点 New,这次切到 Files 标签,类型选C++ Source File,文件名填Exe1_1_1.cpp,扩展名系统会自动补。这里有个复选框叫Add to project,必须勾上,它决定这个文件是不是当前项目的一部分。
不勾的后果很典型:文件建出来了,代码也能写,一按编译,提示找不到main函数或者直接编译了另一个空项目。原因是文件存在磁盘上但没进项目,编译器根本没读它。判断方法很简单,看左侧工作区窗口的树形结构,文件应该挂在Source Files节点下面。看不见就是没加进去,用Project菜单里的Add To Project→Files手动补。
建好之后工作区会分成三块:左边项目树、右边编辑窗口、下边输出窗口。输出窗口后面会频繁用到,编译错误、链接错误、调试信息全在这里显示,实验一里至少要读它十几次。
3.3 实验一的菜单程序:把框架补完
指导书在验证分析部分给了一段不完整的代码,要求补全后输出图书管理系统主菜单。这段代码是整门课的第一个可运行成果,也是后面图书管理系统的入口雏形。补完的版本如下:
// Exe1_1_1.cpp —— 实验一,输出图书管理系统主菜单 #include <iostream.h> int main() { // 上边框和标题,用同一串星号保持对齐 cout << "*******************************************" << endl; cout << " 图书管理系统主菜单" << endl; cout << "*******************************************" << endl; // 提示语与四个功能项,编号后面跟两个短横线,和指导书一致 cout << "请按照需求选择相应功能的编号,并按回车键执行!" << endl; cout << "1-- 添加新书" << endl; cout << "2-- 查询图书" << endl; cout << "3-- 删除图书" << endl; cout << "4-- 退出" << endl; cout << "*******************************************" << endl; return 0; }代码里用的是#include <iostream.h>而不是新标准里的<iostream>加using namespace std,这不是写错。VC++ 6.0 带的编译器对 C++ 标准支持得比较早,<iostream.h>这种老式头文件在这套环境里直接可用,改成新写法反而要处理命名空间和头文件兼容问题。做实验阶段,跟着指导书的写法走最省事;如果要拿去别的编译器上用,再改也不迟。
endl的作用是换行并刷新输出缓冲,控制台程序里和'\n'效果接近,但刷新这一点在调试时有用,程序崩溃前已经输出的内容不会留在缓冲区里丢掉。
3.4 编译、连接、运行:三个动作分别看什么
按 Build 菜单里的 Compile 是只编译当前文件,生成.obj;按 Build 是编译加连接,生成.exe;按 Execute 是运行。快捷键 Ctrl+F5 一步完成编译、连接、运行,实验阶段最常用。
整个过程里输出窗口会给三种信息,要分清:
编译错误通常是语法问题,格式是文件名(行号) : error CXXXX: 描述,比如漏分号、变量没定义、头文件找不到。这类错误必须全部清掉,程序才能继续。链接错误出现在编译通过之后,格式是LNK开头,典型的是LNK2001: unresolved external symbol,意思是某个函数声明了但没实现,或者实现它的文件没加进项目。运行期错误不报编译错误,程序能启动但结果不对或者直接崩,这类只能靠调试器。
运行的时候窗口一闪而过是新手最常见的困惑。原因不是程序没运行,是它跑完return 0就退出,控制台窗口跟着关掉。解决办法有两个:在return 0前面加一句cin.get();让程序等一次输入,或者在 IDE 里用 Ctrl+F5 启动(这种方式运行结束后会停住并提示按任意键)。指导书里提到的Ctrl+F5就是这个用途,不要用 F5 直接跑,F5 是调试模式,没设断点的话一样一闪而过。
程序输出和指导书上的参考结果对齐之后,实验一就算完成。别急着往下走,回头把工程目录看一遍:.dsw、.dsp、.cpp、.obj、.exe都在,Debug文件夹里是中间产物。这套结构会在后面四个实验里反复出现,认清楚了后面能省很多时间。
4. 五个实验共用一套工程骨架:头文件、多文件与调试配置
4.1 实验二的分文件约定:mytype.h 与 login.cpp
实验二的要求里写得很具体:在自定义的头文件mytype.h中完成类的定义,建立主函数存入login.cpp,完成对象的创建。这个约定不是随便定的,它是从实验一那种“一个文件写完”过渡到“声明与实现分离”的第一步,也是后面图书管理系统能继续长大的前提。
头文件里放类的声明,.cpp里放成员函数的实现和主函数,这是 C++ 工程的基本组织方式。VC++ 6.0 对这个结构支持得没问题,但有两个细节要注意:一是头文件必须写包含守卫,否则同一个头文件被两个源文件包含时会出现重复定义;二是源文件包含头文件时用双引号"mytype.h"而不是尖括号,双引号先搜当前目录,尖括号只搜系统目录。
// mytype.h —— 实验二:图书管理系统的类声明,先只放一本书的模型 #ifndef MYTYPE_H // 包含守卫,防止重复包含导致的重复定义 #define MYTYPE_H #include <iostream.h> #include <string.h> class Book { private: char name[40]; // 书名 char author[20]; // 作者 int count; // 库存册数 public: Book(); // 默认构造函数 Book(const char *n, const char *a, int c); // 带参构造 Book(const Book &b); // 拷贝构造,实验二要观察它的调用时机 ~Book(); // 析构函数 void Show() const; // 输出一本书的信息 }; #endif// login.cpp —— 实验二的入口文件,建对象、调成员函数 #include "mytype.h" Book::Book() { name[0] = '\0'; // 字符数组没法整体赋值,用首字符置空表示空串 author[0] = '\0'; count = 0; } Book::Book(const char *n, const char *a, int c) { strcpy(name, n); // 逐个字符拷进来,不能直接 name = n strcpy(author, a); count = c; } Book::Book(const Book &b) // 拷贝构造:用已有对象初始化新对象时被调用 { strcpy(name, b.name); strcpy(author, b.author); count = b.count; } Book::~Book() // 析构函数,对象生命周期结束时自动执行 { } void Book::Show() const { cout << name << " / " << author << " / " << count << endl; } int main() { Book b1; // 调默认构造 Book b2("C++程序设计", "某编者", 5); // 调带参构造 Book b3(b2); // 调拷贝构造 b1.Show(); b2.Show(); b3.Show(); return 0; }这段代码对应实验二“观察构造函数和析构函数的执行过程”的要求。运行起来只能看到Show的输出,看不到构造和析构的调用顺序,因为函数体是空的。想看顺序,就在每个函数体里加一句cout,或者在调试器里打断点。指导书里提到用 Debug 功能跟踪执行顺序,就是这个意思:单靠读代码很难确认构造和析构的先后,必须让程序停下来看。
count用int而不是字符串存,name和author用定长字符数组而不是char*,这是实验阶段的取舍。定长数组不用管内存释放,析构函数可以是空的,实验二的重点在构造函数和对象生命周期上,不在这里引入动态内存,能少一层出错的可能。等做到实验四、实验五,如果确实需要变长字符串,再换成指针加new/delete的写法。
4.2 实验三到实验五:多文件工程怎么加、怎么排
实验三开始出现类的派生,例子里有Date、Time派生出的DateTime,还有Base派生出AllChil、Men、OldMen这类层次。代码量比实验二大一截,再堆在一个.cpp里,编译一次要等很久,改一行报错位置也难找。合理的做法是把每个类族拆成一组.h加.cpp,然后在同一个工程里编译。
在 VC++ 6.0 里给项目加多个文件,走Project菜单的Add To Project→Files,一次可以选多个。加进来之后左侧项目树的Source Files和Header Files会分别列出它们。这时候要养成一个习惯:每加一个文件,立刻按一次 Build 确认能过。一次性加五六个文件再编译,报错会混在一起,排查成本高很多。
多文件工程里有两条容易踩的规则。第一,整个工程只能有一个main函数。实验二到实验五每一份练习都有自己的main,如果把它们全加进同一个项目,链接时必然报LNK2005: _main already defined。我一般的处理是每个实验单独建一个工程,共用一个目录结构,不共用一个项目文件。第二,头文件里只放声明,不放函数定义。放定义的头文件被两个.cpp包含时,链接阶段会出现重复符号,错误信息看起来和“函数没实现”很像,容易误判。
实验四涉及多态和虚函数,代码结构上要注意基类的虚函数必须在派生类里用相同签名覆盖,参数类型、个数、const修饰都要一致,差一个const就不构成覆盖,而是一个新函数,运行时不会走动态绑定。这个错误编译器不报,只能靠运行时结果异常发现。实验五涉及输入输出流,fstream读写文件时路径用相对路径,文件放在工程目录下,别写绝对路径,换台机器就找不到文件。
4.3 调试配置:断点、单步和 Watch 窗口里的 this
实验二明确要求用 VC++ 的 debug 功能观察构造函数、析构函数、成员函数的执行顺序,实验四要求观察多态调用实际走的是哪个函数。这两类观察都只能用调试器做,光看代码得不出结论。
基本操作是:在代码行号左边的灰色区域点一下设断点,按 F5 启动调试,程序停到断点处,然后 F10 单步执行(遇到函数调用不进去),F11 单步进入函数内部,Shift+F11 从当前函数返回。执行到哪一行,左边会有黄色箭头标出来。
看对象内部状态靠 Watch 窗口。调试状态下在 Watch 窗口输入变量名,就能展开看到它的成员。成员函数里输入this,展开后能看到当前对象的全部数据成员,这一点在实验二里特别有用:构造和析构执行到哪一步,成员的值是什么,一眼就能看出来。配合Call Stack窗口还能看到函数调用链,确认是哪一个构造先被调用。
调试配置本身也有坑。VC++ 6.0 默认的 Debug 配置会生成调试信息,如果切到 Release 配置,断点会被忽略,提示“不能设置断点”。做实验期间不要动配置下拉框,保持在Win32 Debug。另外,程序运行中改了代码不要直接重新编译,先停掉正在跑的程序,否则.exe被占用,链接阶段报LNK1104: cannot open file。
4.4 交实验报告前的目录清理
指导书里强调实验报告要按附录格式写,内容详实、数据准确、分析全面。报告里通常要贴源程序清单和运行结果截图,所以交之前得把工程目录整理一遍。
Debug文件夹里是.obj、.ilk、.pdb这类中间文件,不用交也不用删,它下次编译还会生成。要确认的是.dsw、.dsp、所有.cpp和.h都在,并且工程能从头编译通过。最稳的验证方式是Build菜单里的Rebuild All,它会先清空再全量编译,能暴露增量编译掩盖掉的问题。
截图之前把控制台窗口调成固定大小,避免每次截出来尺寸不一。运行结果和程序输出要能对得上,报告里的分析才有依据。
5. 装完不出活?这几类现场我遇到过不止一次
5.1 双击图标没反应,任务管理器里也看不到进程
现象:装完之后双击桌面图标,鼠标转一下就没了,什么都不弹。
原因:多数是兼容性没设,主程序在新系统上启动时被拦住了,另外安装时如果没用管理员权限,注册表里的组件注册信息是缺的,IDE 初始化阶段就退出了。
解决:右键MSDEV.EXE属性,兼容模式选 Windows XP SP3,勾上以管理员身份运行,再启动。还不行就用管理员权限重新跑一次安装程序的修复选项。这类问题不要靠重装系统解决,八成就是权限和兼容模式两件事。
5.2 编译报 C1083 找不到 iostream.h
现象:代码明明写着#include <iostream.h>,编译直接失败,提示fatal error C1083: Cannot open include file: 'iostream.h': No such file or directory。
原因:要么INCLUDE环境变量没指向VC98\Include,要么安装时只装了 IDE 没装编译器组件,要么项目设置里被手动改过附加包含路径。
解决:先在命令行执行dir C:\VC6\VC98\Include\iostream.h确认文件存在。存在就是路径问题,补INCLUDE环境变量后重开 IDE;不存在就是组件没装,回安装程序补装 Visual C++ 6.0 本体。
5.3 链接报 LNK2005 或 LNK2001
现象:编译全部通过,链接阶段报_main already defined或者unresolved external symbol。
原因:前者是同一个工程里塞了两个以上的main函数,多半是把实验二和实验三的入口文件加进了同一个项目;后者是函数声明了但没实现,或者实现所在的.cpp没加进项目。
解决:一个工程只留一个main,其余实验各自建工程。未解析符号就去看对应函数的实现文件是否在项目树里,没在就用Add To Project加进去。判断依据是项目树的文件列表,不是磁盘上有没有这个文件。
5.4 Ctrl+F5 运行,窗口一闪就没了
现象:编译链接都成功,Ctrl+F5 之后黑窗口闪一下消失,看不到任何输出。
原因:程序执行完return 0就退出,控制台窗口随之关闭,这是正常行为,不是程序没跑。
解决:在return 0前加cin.get();等一次回车,或者改用 Ctrl+F5 启动并在结束后按任意键。如果加了还是闪,说明程序在输出之前就崩了,这时候要用 F5 加断点定位,别继续加等待语句。
5.5 中文注释变成乱码,或者编译报非法字符
现象:昨天写好的注释,今天打开是一堆看不懂的符号;或者编译时提示某行有非法字符,但那一行看起来就是普通的中文注释。
原因:VC++ 6.0 默认按本地编码读写源文件。用别的编辑器把文件存成了 UTF-8,回来打开就乱码。另一个常见原因是中文标点,比如全角分号、全角括号混进了代码行。
解决:统一用 IDE 自带的编辑器改文件,不要用外部编辑器来回改。已经乱码的,把注释删掉重写一遍再保存。编译报非法字符就逐行看标点,代码里的分号、括号、引号必须是半角。
6. 验收:用实验一那段菜单程序做一次端到端复现
环境装完、工程建完,最后要有一个明确的“跑通了”的判断标准,不然很容易停在“好像能编译”的状态。我的验收方式是把实验一那段菜单程序从零重做一遍,中间不复制粘贴,全部手打。这个流程能把路径、工程、源文件、编译、运行五个环节一次性验证完。
验收按下面这张表逐项过,任何一项不符合就回头查对应章节:
| 检查项 | 操作 | 预期结果 |
|---|---|---|
| 工具链可用 | 命令行执行cl toolcheck.cpp | 生成 exe,运行打印 toolchain ok |
| IDE 可启动 | 双击设过兼容性的快捷方式 | 正常出现三块窗口,菜单可点 |
| 工程可建 | New → Projects → Win32 Console Application | 目录下生成 .dsw 与 .dsp |
| 文件进项目 | 新建 .cpp 时勾选 Add to project | 项目树 Source Files 下能看到该文件 |
| 编译无错 | 按 Build | 输出窗口显示 0 error(s), 0 warning(s) |
| 运行正确 | 按 Ctrl+F5 | 窗口输出完整菜单并停住 |
最后一步的运行结果要和指导书里的参考输出逐行对照,星号数量、提示语、四个编号项一个都不能少。这里不需要做任何美化,对齐就行,实验报告里贴的也是这个画面。
有几个收尾动作值得固定成习惯。第一,每次改完代码先Rebuild All再截图,增量编译有时候会用旧的.obj,跑出来的结果和你屏幕上的代码对不上,事后复盘能查很久。第二,每个实验单独一个工程目录,命名带上实验编号,别全堆在一个文件夹里,链接冲突多半是这么来的。第三,.dsw和.dsp跟源文件一起备份,这两个文件丢了,重新配一遍工程比重写代码还费时间。
从那以后我每次装这套环境,都是先跑命令行那条cl验证,再进 IDE 建工程,最后用实验一的菜单程序收尾,三步走完才动实验二的代码。跳过任何一步,后面都会以某种奇怪的形式还回来,比如编译能过但调试器挂不上,比如断点设了不生效,查到最后发现是环境变量里少了一条。这套流程不复杂,但顺序不能乱。希望帮到你。
本文还有配套的精品资源,点击获取