《C++ 程序设计》期末模拟卷 C(偏概念与陷阱版)
满分:100 分 | 建议用时:120 分钟。题型与分值:一、单项选择题 18 题 × 1 分 = 18 分;二、读程序写输出 7 题 × 5 分 = 35 分;三、程序填空题 4 题(共 17 空)= 17 分;四、编程题 3 题 × 10 分 = 30 分。本卷为「偏概念与陷阱版」,强化单选与程序填空,密集覆盖招牌易错点(switch 穿透、static 跨调用记忆性、构造/析构调用次序与次数、对象切片、深拷贝 operator= 自赋值、运算符重载与友元、动态内存数据结构)。
已知 int x = 7, y = 2;,则表达式 x / y * 2.0 + x % y 的值是:
7.0
6.0
7
8.0
设 unsigned char c = 250;,执行 c += 10; 后,c 的值为:
260
4
255
编译错误
下列关于 '\0'、'0'、"0"、NULL 的说法中,正确的是:
'\0' 与 '0' 是同一个字符
"0" 在内存中只占 1 个字节
'\0' 是字符串结束标记,其 ASCII 值为 0
NULL 与字符 '0' 等价
阅读如下代码段:
int n = 5;
switch (n / 2) {
case 1: cout << "A";
case 2: cout << "B"; break;
case 3: cout << "C";
default: cout << "D";
}
输出为:
AB
B
CD
BD
关于函数重载,下列说法正确的是:
函数名相同、仅返回类型不同即可构成重载
函数名相同、参数表(个数或类型)不同可构成重载
重载函数必须定义在同一个类中
默认参数会破坏函数重载,因此二者不能同时使用
设 int a[5] = {10, 20, 30, 40, 50}; int *p = a;,则 *(p + 3) - *p 的值是:
30
3
40
地址差(与机器相关)
关于 const 与指针,下列声明中不能通过指针修改其所指对象的是:
int * const p = &a;
const int *p = &a;
int *p = &a;
以上三者都可以通过指针修改
执行语句 AB a(2), b[3], *p[4];(AB 仅有一个带参构造函数),共调用构造函数的次数是:
8
5
4
3
下列运算符中,只能重载为成员函数、不能重载为友元(全局)函数的是:
+
==
=
<<
关于静态数据成员(static 数据成员),下列说法错误的是:
它被该类的所有对象共享
它必须在类外单独定义并分配空间
静态成员函数中可以直接访问非静态数据成员
static const int 成员可在类内初始化
已知类 D 是类 B 的公有派生类,D *pd, d; B *pb, b;,下列赋值中不合法(不符合赋值兼容规则)的是:
pb = pd;
pb = &d;
pd = pb;
b = d;
关于虚函数与多态,下列说法正确的是:
通过对象(而非指针/引用)调用虚函数也能实现动态绑定
构造函数可以声明为虚函数
基类析构函数声明为 virtual 可避免 delete 基类指针时派生部分内存泄漏
纯虚函数所在的类仍可被直接实例化
下列关于深拷贝与浅拷贝的说法,错误的是:
含指针成员的类若只用编译器合成的拷贝构造,可能导致同一块内存被重复 delete
operator= 实现深拷贝时应先判断自赋值,再释放旧空间
浅拷贝会让两个对象的指针成员指向同一块堆内存
只要类中含有指针成员,编译器就会自动为其生成深拷贝
关于异常处理 try / throw / catch,下列说法正确的是:
catch(int) 能捕获 throw 3.5; 抛出的 double 异常(自动类型提升)
异常匹配是按声明顺序逐个进行的精确类型匹配,不做隐式算术转换
一旦 throw,当前已构造的局部对象不会被析构
catch(...) 必须放在所有 catch 块的最前面
关于流操纵符,已知 cout << setw(6) << setfill('*') << 12 << 34 << endl;,输出为:
****1234
****12****34
****1234**
12****34
关于文件流,下列说法错误的是:
ifstream in("data.txt"); 后可用 if (!in) 判断打开是否失败
while (in >> x) 在读到文件尾或读取失败时结束循环
以 ofstream 默认方式打开一个已存在的文件,会清空原有内容
ifstream 默认以 ate 模式打开,读指针位于文件尾
设有 char s[] = {'1', '2', '3', '\0', '4', '5'};,执行 cout << s; 的输出是:
123
12345
123 45
12345 后跟乱码
关于组合(成员对象)类的构造与析构次序,下列说法正确的是:
成员对象按初始化列表中书写的先后顺序构造
成员对象按其在类中声明的顺序构造,按相反顺序析构
先执行本类构造函数体,再构造成员对象
析构次序与构造次序相同
(switch 穿透 + 整数除法)
#include <iostream>
using namespace std;
int main() {
for (int m = 1; m <= 5; m++) {
int n;
switch (m % 3) {
case 0: n = 10;
case 1: n = 20; break;
case 2: n = 30;
default: n = 40;
}
cout << n << " ";
}
cout << endl;
return 0;
}
(static 局部变量跨调用 + 引用/值传参)
#include <iostream>
using namespace std;
void calc(int a, int &b) {
static int s = 1;
s += a;
a = a + b;
b = s + a;
}
int main() {
int x = 2, y = 3;
calc(x, y);
cout << x << " " << y << endl;
calc(x + 1, y);
cout << x << " " << y << endl;
return 0;
}
(构造/拷贝构造/析构调用次序与次数 + 局部 static 对象)
#include <iostream>
using namespace std;
class Item {
char id;
public:
Item(char c) : id(c) { cout << "ctor " << id << endl; }
Item(const Item &o) : id(o.id) { cout << "copy " << id << endl; }
~Item() { cout << "dtor " << id << endl; }
};
void use() {
static Item a('a');
Item b('b');
}
int main() {
Item *p = new Item('p');
use();
delete p;
use();
cout << "end main" << endl;
return 0;
}
(虚函数多态 vs 对象切片)
#include <iostream>
using namespace std;
class Base {
public:
virtual void who() { cout << "Base "; }
void tag() { cout << "B-tag "; }
};
class Derived : public Base {
public:
void who() { cout << "Derived "; }
void tag() { cout << "D-tag "; }
};
int main() {
Derived d;
Base *pb = &d;
Base ob = d; // 对象赋值,发生切片
pb->who(); pb->tag();
ob.who(); ob.tag();
cout << endl;
return 0;
}
(运算符重载:前置/后置 ++ 与友元 <<)
#include <iostream>
using namespace std;
class Counter {
int v;
public:
Counter(int x = 0) : v(x) {}
Counter& operator++() { v += 2; return *this; } // 前置
Counter operator++(int) { Counter t = *this; v += 2; return t; } // 后置
friend ostream& operator<<(ostream &os, const Counter &c) {
os << c.v; return os;
}
};
int main() {
Counter c(5);
cout << c++ << " " << c << " ";
cout << ++c << " " << c << endl;
return 0;
}
(指针与数组 / 字符指针偏移)
#include <iostream>
using namespace std;
int main() {
const char *words[] = {"apple", "banana", "cherry"};
cout << words[1] + 2 << endl;
cout << *(words[0] + 1) << endl;
cout << words[2][3] << endl;
return 0;
}
(异常处理:精确类型匹配 + 抛出时对象析构)
#include <iostream>
using namespace std;
class Guard {
int id;
public:
Guard(int i) : id(i) { cout << "in " << id << " "; }
~Guard() { cout << "out " << id << " "; }
};
void run(int code) {
Guard g(1);
if (code == 0) throw 100; // int
else throw 2.5; // double
}
int main() {
try {
run(1);
} catch (int e) {
cout << "catch int " << e << " ";
} catch (double e) {
cout << "catch double " << e << " ";
}
cout << endl;
return 0;
}
(含指针成员的 MyString 类——深拷贝三件套,5 空)
要求:MyString 自管理一段 C 风格字符串,下面补全带参构造、拷贝构造、赋值运算符,使其满足三法则(深拷贝、防自赋值、无内存泄漏)。
#include <cstring>
class MyString {
char *str;
public:
MyString(const char *s) {
str = new char[__①__];
strcpy(str, s);
}
MyString(const MyString &o) {
str = new char[strlen(o.str) + 1];
__②__;
}
MyString& operator=(const MyString &o) {
if (__③__) return *this; // 防自赋值
__④__; // 释放旧空间
str = new char[strlen(o.str) + 1];
strcpy(str, o.str);
return __⑤__;
}
~MyString() { delete[] str; }
};
(二分查找补全,4 空)
要求:在升序整型数组 a 中查找 target,找到返回下标,否则返回 -1。
int binarySearch(int *a, int len, int target) {
int left = 0, right = len - 1, mid;
while (__①__) {
mid = left + (right - left) / 2;
if (a[mid] == target) return __②__;
else if (a[mid] > target) __③__;
else __④__;
}
return -1;
}
(文件读取与统计行数,4 空)
要求:打开文本文件 fname,逐个读取以空白分隔的单词并输出,统计单词个数;打开失败时输出 open error。
#include <fstream>
#include <iostream>
using namespace std;
void readWords(const char *fname) {
__①__ fin(fname);
char word[64];
int cnt = 0;
if (__②__) { cout << "open error"; return; }
while (__③__) {
cout << word << endl;
cnt++;
}
cout << "total = " << cnt << endl;
__④__;
}
(const 数据成员 + 递归求和,4 空)
要求:Box 含 const int cap(容量),必须用初始化列表初始化;sumTo 用递归求 1+2+...+n。
class Box {
const int cap;
public:
Box(int c) __①__ {} // 用初始化列表初始化 cap
int capacity() const { return cap; }
};
int sumTo(int n) {
if (__②__) return 0; // 递归出口
return __③__ + __④__; // 当前项 + 递归调用
}
(运算符重载 + 友元:Money 金额类,第 10 章)
设计一个金额类 Money,以「元」yuan 和「分」fen(0–99)两个整型成员表示。要求:
- 提供构造函数(可设默认值),并在构造时把
fen ≥ 100的部分进位到yuan; - 重载成员运算符
operator+,实现两个Money相加(分满 100 进位为元); - 重载友元
operator<<,按X.YY 元格式输出(分不足两位补前导 0,如12.05 元); - 提供友元函数
Money average(const Money &a, const Money &b),返回两金额的平均值(向下取整到分)。
在 main 中构造两个 Money,输出它们的和与平均值。
(递归:删除字符串中的指定字符,第 6 章)
编写函数 void delChar(char str[], char c);,删除 C 风格字符串 str 中出现的所有字符 c,要求用递归实现,不得使用循环(库函数 strlen 等可用,但删除逻辑必须递归)。删除后字符串仍以 '\0' 结尾。
例如 str = "banana", c = 'a' 处理后 str 变为 "bnn"。在 main 中读入一行字符串与一个字符,调用并输出结果。
(动态内存数据结构 + 三法则:有序整型数组类 SortedArray,第 7 / 10 章)
设计一个动态有序整型数组类 SortedArray,内部用 int *data 指向堆内存,size 表示当前元素个数,cap 表示容量。要求:
- 构造函数申请初始容量的堆空间;析构函数释放;
void insert(int x):将x按升序插入到正确位置(保持有序,不是简单尾插);容量不足时倍增扩容;- 实现拷贝构造函数与赋值运算符
operator=,均为深拷贝,operator=须防自赋值; int operator[](int k) const:返回第k小的元素(即下标k处元素)。
在 main 中乱序插入若干整数,按从小到大输出,演示拷贝/赋值后两对象互不影响。