《C++ 程序设计》期末模拟卷 A(均衡·标准考点版)
满分 100 分 建议用时 120 分钟。题型与分值:一、单项选择题 18 题 × 1 分,共 18 分;二、读程序写输出 7 题 × 5 分,共 35 分;三、程序填空 约 15 空,共 17 分;四、编程大题 3 题 × 10 分,共 30 分。本卷为均衡·标准考点版,覆盖第 2–14 章四种题型与各难度,最贴近真实期末形态。参考答案与解析见文末(前端默认折叠,自测后再展开)。
下列关于 '\0'、'0'、"0"、0 的说法正确的是?
'0' 与 '\0' 的内码值相同
"0" 在内存中占 1 个字节
'\0' 是字符串结束标记,其 ASCII 值为 0
NULL 与 '\0' 是完全等价的写法
设 int a = 7, b = 2;,下列表达式结果为 double 类型且值为 3.5 的是?
a / b
a / b * 1.0
(double)(a / b)
(double)a / b
执行以下语句后,输出的是?
int x = 0;
switch (x) {
case 0: x += 1;
case 1: x += 2; break;
case 2: x += 4;
default: x += 8;
}
cout << x;
1
3
11
7
关于 for (int k = 0; k < 3; ++k); 这条语句,下列说法正确的是?
这是语法错误
行末的分号使循环体为空语句,循环结束后 k 为 3
循环将无限执行
循环体只执行一次
下列哪个运算符不能重载为友元(全局)函数?
+
==
=
<<
已知 D 是 B 的公有派生类,定义 D *pd, d; B *pb, b;,下列赋值不符合赋值兼容规则的是?
pb = pd;
pb = &d;
pd = pb;
b = d;
关于 const 与指针,设 int m = 1, n = 2;,下列说法正确的是?
const int *p = &m; 之后可以执行 *p = 5;
int * const p = &m; 之后可以执行 p = &n;
int * const p = &m; 之后可以执行 *p = 5;
const int *p = &m; 定义时可以不初始化
执行 AB a(2), b[3], *p[4];(AB 含一个带 int 参数的构造函数),共调用构造函数几次?
8
5
4
3
关于 static 局部变量,下列说法错误的是?
未显式初始化时自动初始化为 0
函数调用结束后仍然存在,下次调用保留上次的值
其作用域仍局限于定义它的函数内
每次进入函数都会重新初始化一次
设 char *city[] = {"sea", "moon", "glass", "river"};,则 cout << city[2] + 1; 的输出是?
lass
glass
l
'l'
关于类的静态数据成员,下列说法正确的是?
静态数据成员被该类的所有对象共享
静态数据成员只能在构造函数初始化列表中初始化
每个对象都拥有独立的一份静态数据成员
静态数据成员不需要在类外单独定义即可使用
关于常量成员函数(const 成员函数),下列说法正确的是?
常量对象既能调用常量成员函数,也能调用普通成员函数
常量成员函数内可以修改本对象的非静态数据成员
常量对象只能调用常量成员函数
普通对象不能调用常量成员函数
关于虚函数与多态,下列说法正确的是?
通过对象(非指针/引用)调用虚函数也能实现动态绑定
只有通过基类的指针或引用调用 virtual 函数时才发生动态绑定
析构函数不允许声明为 virtual
纯虚函数所在的类可以被实例化为对象
关于异常处理 throw / try / catch,下列说法正确的是?
catch 的匹配会进行隐式类型提升,throw 3(int)可被 catch(double) 捕获
一个 try 块只能跟随一个 catch 子句
catch(...) 可以捕获任意类型的异常
throw 抛出异常后,当前作用域中已构造的局部对象不会被析构
关于类模板,下列说法错误的是?
类模板必须先实例化为具体类型后才能定义对象
template <class T> 中的 T 是类型参数
同一个类模板用不同类型实例化得到的是同一个类
类模板的成员函数本身也是函数模板
关于派生类的构造与析构顺序,下列正确的是?
构造顺序为:派生类 → 对象成员 → 基类
构造顺序为:基类 → 对象成员 → 派生类,析构顺序与之相反
析构函数会被继承到派生类中
派生类不需要负责从基类继承来的数据成员的初始化
关于文件输入流 ifstream,下列用法正确的是?
ifstream fin("data.txt"); 后用 if (fin) 判断打开是否成功
文件流对象使用完毕后无需关闭
ifstream 默认以 out 模式打开
while (fin >> x) 在读到文件中第一个数据后立即终止
设 int a[5] = {0}; int *p = a;,关于指针算术,下列说法正确的是?
p + 2 与 (char*)p + 2 指向同一地址
p + 2 相对 p 在地址上前进了 2 个字节
*(p + 2) 等价于 a[2]
数组名 a 可以被重新赋值为另一个数组的地址
(构造/拷贝构造/析构调用追踪)写出下列程序的完整输出。
#include <iostream>
using namespace std;
class Box {
int id;
public:
Box(int i) : id(i) { cout << "ctor " << id << endl; }
Box(const Box &b) : id(b.id) { cout << "copy " << id << endl; }
~Box() { cout << "dtor " << id << endl; }
};
Box make(int n) {
Box t(n);
return t;
}
int main() {
Box a(1);
Box b = make(2);
cout << "---" << endl;
return 0;
}
提示:现代编译器可能因返回值优化省略拷贝;本题按未启用 NRVO、严格按语义作答,
return t;触发一次拷贝构造、t随后析构。
(switch 穿透)写出下列程序的输出。
#include <iostream>
using namespace std;
int main() {
for (int m = 0; m <= 4; ++m) {
int n;
switch (m) {
case 0:
case 2: n = 10; break;
case 1: n = 20;
case 3: n = 30; break;
default: n = 40;
}
cout << n << " ";
}
return 0;
}
(static 局部变量 + 引用 vs 值传参)写出下列程序两行输出。
#include <iostream>
using namespace std;
void g(int x, int &y) {
static int s = 1;
s += x;
x = x + s;
y = y + s;
}
int main() {
int a = 3, b = 5;
g(a, b);
cout << a << " " << b << endl;
g(a + 1, b);
cout << a << " " << b << endl;
return 0;
}
(虚函数多态 vs 对象切片)写出下列程序的输出。
#include <iostream>
using namespace std;
class Animal {
public:
virtual void say() { cout << "Animal" << endl; }
};
class Cat : public Animal {
public:
void say() { cout << "Cat" << endl; }
};
int main() {
Cat c;
Animal *p = &c;
Animal &r = c;
Animal o = c; // 对象切片
p->say();
r.say();
o.say();
return 0;
}
(流操纵符作用范围)写出下列程序的输出。
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int n = 255;
cout << setfill('-') << setw(8) << "A" << n << endl;
cout << hex << n << endl;
cout << n << endl;
return 0;
}
提示:
setw只对其后第一次输出有效,setfill与进制设置持续生效。
(递归)写出下列程序的输出。
#include <iostream>
using namespace std;
void f(int n) {
if (n == 0) return;
cout << n % 2;
f(n / 2);
}
int main() {
f(13);
cout << endl;
return 0;
}
(运算符重载 + 类型转换)写出下列程序的输出。
#include <iostream>
using namespace std;
class Frac {
int a, b;
public:
Frac(int x = 0, int y = 1) : a(x), b(y) {}
Frac operator+(const Frac &r) const {
return Frac(a * r.b + r.a * b, b * r.b);
}
operator double() const { return double(a) / b; }
friend ostream& operator<<(ostream &os, const Frac &f) {
os << f.a << "/" << f.b;
return os;
}
};
int main() {
Frac x(1, 2), y(1, 3);
Frac z = x + y;
cout << z << endl;
cout << z + 1.0 << endl;
return 0;
}
(String 类深拷贝三件套,第 10 章,5 分)下面是一个自管理 char* 的字符串类,补全 3 处使其满足"三法则"(深拷贝赋值含自赋值判断)。
#include <cstring>
class MyStr {
char *str;
public:
MyStr(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
MyStr& operator=(const MyStr &s) {
if (______(1)______) return *this; // 自赋值判断
______(2)______; // 释放原有空间
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
return ______(3)______;
}
~MyStr() { delete[] str; }
};
(二分查找补全,第 7 章,4 分)数组 a 升序排列,补全二分查找。
int bsearch(int *a, int len, int target) {
int left = 0, right = len - 1, mid;
while (______(4)______) {
mid = left + (right - left) / 2;
if (a[mid] == target) return mid;
else if (______(5)______) ______(6)______;
else left = mid + 1;
}
return -1;
}
(文件流读取,第 14 章,4 分)从文本文件逐个读入整数并求和。
#include <fstream>
#include <iostream>
using namespace std;
int sumFile(const char *fname) {
______(7)______ fin(fname); // 定义输入文件流
if (______(8)______) { // 判断打开失败
cout << "open error";
return -1;
}
int x, sum = 0;
while (______(9)______) sum += x; // 逐个读入
______(10)______; // 关闭文件
return sum;
}
(const 数据成员 + static 成员 + 引用传参,第 10 章,4 分)补全使总重量统计正确。
class Goods {
const int weight;
static int totalWeight;
public:
Goods(int w) : ______(11)______ { totalWeight += weight; }
~Goods() { totalWeight -= weight; }
static int total() { return totalWeight; }
};
______(12)______; // 在类外定义并初始化静态成员
void show(______(13)______ g) { // 以引用传参,避免拷贝/析构改变 totalWeight
cout << Goods::total() << endl;
}
(递归,第 6 章,10 分)
编写函数 void squeeze(char str[], char c),用递归实现:删除以 '\0' 结尾的字符串 str 中所有等于 c 的字符,结果仍存回 str(原地修改)。不得使用循环语句(for/while/do),不得使用 <cstring> 之外的库容器。例如 str = "banana"、c = 'a',调用后 str 变为 "bnn"。
要求:
- 递归边界正确(空串);
- 命中字符时正确地把后续字符整体前移一位再继续递归;
- 给出可直接编译运行的
main测试一例。
(运算符重载 + 友元的完整类设计,第 10 章,10 分)
设计一个商品类 Goods,含数据成员:名称 name(string)、单价 price(double)、数量 count(int)。要求实现:
- 合适的构造函数;
- 成员运算符
operator+:将两个商品的总额(price * count)相加,返回一个新的Goods(名称取"sum"、count置 1、price为两者总额之和); - 友元
operator<<:按name price count格式输出; - 友元函数
double avgPrice(const Goods &x, const Goods &y):返回两商品单价的平均值。
给出完整类定义与各函数实现(可附简单 main)。
(抽象类 + 多态层次,第 12 章,10 分)
从抽象基类 Shape 出发设计图形继承层次:
Shape含纯虚函数virtual double area() const = 0;和虚函数virtual void print() const;(打印面积);- 派生
Circle(半径r,面积PI * r * r)与Rectangle(宽w、高h,面积w * h); PI作为类内共享常量(用static const double或等价方式);- 在
main中用基类指针数组存放若干Circle/Rectangle对象,遍历多态调用print(),并正确释放内存(注意基类析构函数应为虚)。
给出完整定义与 main。