🧪 C++ 程序设计 · 考试题库
基于课堂课件与教材 · 共 99 道题
📘 第一章 C++ 初步知识
一、选择题
cin 和 cout 的叙述正确的是?cin/cout 在 iostream 头文件中声明,使用标准库需 using namespace std。
重载允许函数同名但参数个数或类型不同。仅返回值不同不允许,系统无法区分。
不能建立引用的数组,数组是一组连续空间,引用是别名不占据独立空间。
参数个数不同不能用模板。模板声明可用 typename 或 class 关键字,实参类型可自动推导。
二、判断题
using namespace std; 的作用是使用命名空间 std,标准库中的类和函数是在 std 中声明的。不允许参数个数、参数类型都相同,仅返回值不同。系统从调用形式上无法判断匹配哪个函数。
有默认值的形参必须放在形参表右侧,不允许无默认值和有默认值交错排列。
const float PI = 3.14159; 是用 const 定义的常变量,比 #define 更安全(有类型检查)。三、填空题
"\n" 代替。main 函数的类型必须是 ______ 类型。类型 &别名 = 变量名。new 分配数组后,释放时应该用 delete[]。new 分配数组后必须用 delete[] 释放,用 delete 会导致未定义行为。
new 运算符动态分配内存后返回的是 ______。new 返回指向所分配内存的指针,例如 int *p = new int(5);
inline 函数的说法正确的是?类内定义的成员函数默认是 inline 函数。inline 是编译时展开,递归和复杂循环通常不被编译器内联。
:: ?类外定义成员函数必须用 :: 指明所属类,格式为"返回类型 类名::函数名(参数)"。
引用传递时形参是实参的别名,对形参的修改直接影响实参。值传递不改变实参,传指针虽可间接修改但不改变指针本身。
const 定义的常变量必须在 ______ 时初始化。const 变量在定义时就必须初始化,之后不能再赋值修改。
📗 第二章 类和对象
(原Q13-Q24编号不变,以下Q14为新编号)
一、选择题
class 默认是 private,与 struct 默认 public 不同。
类是抽象的(不占内存),对象是具体的(占内存)。类是模板,对象是实例。
格式:类型 类名::函数名(参数表) { }。
三种访问方式:对象名.成员名、指针->成员名、对象的引用.成员名。类名::成员名用于访问静态成员。
二、判断题
int x = 5; 是允许的。类只是定义一种结构(样板),不分配存储空间,因此不能对数据成员初始化。
三、填空题
struct 默认 public,class 默认 private。
struct 默认 public,class 默认 private。这是两者在 C++ 中唯一的本质区别。
this 指针的说法正确的是?this 指针指向当前调用成员函数的对象自身,不能在静态成员函数中使用,也不能被赋值修改。
this 指针。非静态成员函数中都隐含 this 指针(作为第一个参数传入),指向调用该函数的对象。
struct 和 class 的区别是?struct 默认访问权限是 public,class 默认是 private。这是两者在 C++ 中唯一的本质区别。
-> 运算符访问对象的公有成员。对象指针通过 -> 访问公有成员是 C++ 的标准用法,格式为 指针->成员名。
vector 需要包含的头文件是?vector 定义在头文件 <vector> 中,使用时需要 #include <vector>。
📙 第三章 关于类和对象的进一步讨论
(原Q25-Q36编号不变,以下Q26为新编号)
一、选择题
构造函数没有返回值,也不需要写 void。
析构函数名为 ~类名,无返回值、无形参、不能重载,一个类只有一个析构函数。
类似栈结构:后进先出。先构造的对象后析构,后构造的对象先析构。
静态成员被所有对象共享,必须在类外定义和初始化,可以用 类名::静态成员名 访问。
二、判断题
一个类可以有多个构造函数,但创建对象时系统仅执行其中一个。
友元关系是单向的,不能传递。
静态成员函数属于类,与具体对象无关,因此不能直接访问非静态成员(非静态成员属于具体对象)。
三、填空题
📕 第四章 运算符重载
一、选择题
不能重载的 5 个运算符:. .* :: sizeof ?:
cout << 对象 用于自定义类,应重载哪个运算符?流插入运算符 << 和流提取运算符 >> 只能重载为友元函数,因为第一个形参必须是 ostream& 或 istream&,不是自定义类型。
重载不改变优先级和结合性、不改变操作数个数。不能臆造新运算符。
二、判断题
重载不能改变操作数的个数,例如 + 永远是双目运算符。
重载为成员函数时参数个数 = 原操作数个数 - 1(少一个当前对象)。友元函数参数个数 = 原操作数个数。
运算符重载函数不能带默认值参数。
++ 重载时函数参数类型为 ______(占位参数,仅用于区分)。后置++ 的形参写 int(不传值),仅用于和前置++区分。
📘 第五章 继承与派生
一、选择题
派生类构造函数执行顺序:①基类构造函数 ②子对象构造函数 ③派生类构造函数体。
系统调用基类构造函数的顺序就是声明派生类时基类的出现顺序。
菱形继承中基类被继承多次,用虚基类(virtual)使派生类只保留一份共同基类成员。
二、判断题
基类对象不具有派生类的所有成员,所以基类不能赋值给派生类。
通过基类指针只能使用从基类继承的成员,无法访问派生类新增的成员。
三、填空题
最终派生类不仅要负责对其直接基类初始化,还要负责对虚基类初始化。
如果基类没有定义构造函数,或定义了无参构造函数,派生类可以不写基类构造函数,系统自动调默认构造函数。
📗 第六章 多态性与虚函数
(原Q55-Q64编号不变,以下Q57为新编号)
一、选择题
静态多态通过函数重载和运算符重载实现(编译时确定);动态多态通过虚函数实现(运行时确定)。
构造函数不能是虚函数。只有成员函数能声明为虚函数。虚函数在派生类中不强制重新定义。D 描述的是虚函数的核心功能——动态关联。
编译系统在带虚函数的类中增加一个 VPTR 指针(指向函数指针表),因此对象占用的内存增大。
二、判断题
这就是虚函数的核心功能——动态关联。实际调用哪个函数在运行时根据对象的实际类型确定。
抽象类不能实例化,但可以声明指针和引用,指向派生类对象,实现多态。
纯虚函数根本没有函数体,所在的类不能实例化(抽象类)。空的虚函数有函数体,所在类可以实例化。
三、填空题
virtual 函数类型 函数名(参数表)=______;📝 简答题 综合重点
每题 5-8 分,重点考察概念理解与综合分析能力。
条件:函数名相同,但参数个数不同或参数类型不同(或参数顺序不同)。
原因:编译器根据函数调用时传入的实参类型和个数来确定调用哪个函数。如果两个函数的函数名、参数个数、参数类型完全相同,仅返回值不同,编译器无法从调用形式上区分应该调用哪个函数。例如 int f() 和 float f(),调用 f() 时不知道用哪个。
① 值传递:将实参的值复制给形参,形参和实参各自占用独立的内存空间。函数内修改形参不影响实参。
② 指针传递:将实参的地址传递给形参,形参是指针变量。通过指针可以间接修改实参的值,调用时需取地址。
③ 引用传递:形参是实参的别名,形参和实参共享同一块内存。函数内对形参的修改直接影响实参。
引用传递的优点:比指针更直观(不需要取地址和*解引用),比值传递效率高(不产生副本),适合需要修改实参或传递大型对象时使用。
引用:引用是变量的别名,格式为 类型 &别名 = 变量名。引用和被引用的变量共享同一块内存空间。
限制:① 定义引用时必须初始化(不能只声明不赋值);② 一旦初始化,不能改变引用的指向;③ 不能建立引用的数组;④ 不能建立引用的引用;⑤ 不能取引用的地址。
① 抽象:从具体事物中提取共性特征,形成类的过程。如从"张三"、"李四"中抽象出"学生"类。
② 封装:将数据(成员变量)和操作数据的方法(成员函数)捆绑在一起,并隐藏内部实现细节,只对外开放必要的接口。通过访问权限(private/public/protected)实现。
③ 继承:派生类自动获得基类的全部成员,并可新增自己的成员。体现了"is-a"关系,提高了代码复用性。
④ 多态:同一操作作用于不同对象时产生不同的执行结果。静态多态通过函数重载实现,动态多态通过虚函数实现。
this 指针:每个非静态成员函数都有一个隐含的指针参数 this,它指向调用该函数的对象自身。当调用 obj.func() 时,编译器自动将对象的地址传递给 this。
作用:① 在成员函数中通过 this->成员 访问本对象的成员;② 返回当前对象的引用(如 return *this;)。
必须显式使用的情况:当成员函数的形参名与数据成员名相同时,必须用 this->成员 来区分。例如 void set(int x) { this->x = x; }。
构造函数特点:① 函数名与类名相同;② 没有返回值(不写 void);③ 可以重载;④ 创建对象时自动调用;⑤ 如果用户不定义,系统自动生成一个默认构造函数。
析构函数特点:① 函数名为 ~类名;② 没有返回值,没有参数;③ 不能重载(一个类只有一个析构函数);④ 对象销毁时自动调用。
调用顺序:先构造的后析构(栈式)。构造函数:基类构造函数 → 子对象构造函数 → 派生类构造函数体。析构函数:派生类析构函数 → 子对象析构函数 → 基类析构函数。
复制构造函数:用一个已存在的对象来初始化新对象时调用的构造函数。格式为 类名(const 类名 &对象),参数必须是本类对象的引用。
自动调用的情况:① 用已存在的对象初始化新对象(Box box2 = box1;);② 函数参数传值时实参传递给形参;③ 函数返回对象时。
为什么需要自己定义:默认复制构造函数执行浅拷贝(逐个成员复制)。如果类中有指针成员指向 new 出来的内存,浅拷贝会导致两个对象的指针指向同一块内存。析构时先析构的对象 delete 了内存,后析构的对象会重复 delete,导致程序崩溃。自己定义复制构造函数可以执行深拷贝(为新对象重新分配内存并复制内容)。
静态数据成员:① 被所有对象共享,只占用一份内存空间;② 必须在类外定义和初始化(格式:类型 类名::静态成员 = 值);③ 可以通过类名访问(类名::静态成员),也可以通过对象名访问。
静态成员函数:① 属于类本身,与具体对象无关;② 可以直接通过类名调用(类名::静态函数());③ 不能直接访问非静态成员(因为非静态成员属于具体对象,静态函数没有 this 指针)。
不能重载的 5 个运算符:.(成员访问运算符)、.*(成员指针运算符)、::(作用域运算符)、sizeof(长度运算符)、?:(条件运算符)。
规则限制:① 不能改变运算符的优先级和结合性;② 不能改变操作数的个数;③ 不能臆造新的运算符(只能重载已有的);④ 不能改变运算符用于基本类型时的原有语义;⑤ 重载不能带默认值参数;⑥ 重载为成员函数时参数个数 = 原操作数个数 - 1,重载为友元函数时参数个数 = 原操作数个数。
<< 和流提取运算符 >> 必须重载为友元函数形式,而不能重载为成员函数?
因为重载为成员函数时,第一个操作数必须是本类的对象(由 this 指针隐含传递)。而 << 和 >> 的第一个操作数分别是 ostream 对象(如 cout)和 istream 对象(如 cin),它们不是本类类型。所以必须重载为友元函数,将 ostream& 或 istream& 作为第一个显式参数。
此外,重载为友元函数能保证使用习惯 cout << 对象 自然流畅,不需要写成 对象 << cout 这种反直觉的形式。
三种继承方式的影响:
① public 继承:基类的 public 成员在派生类中仍为 public;protected 成员仍为 protected;private 成员不可访问。
② protected 继承:基类的 public 和 protected 成员在派生类中都变为 protected;private 成员不可访问。
③ private 继承:基类的所有成员(public 和 protected)在派生类中都变为 private;private 成员不可访问。
为什么 public 继承最常用:public 继承保持了"is-a"关系(如"学生是一种人"),派生类对象可以当作基类对象使用,支持向上转型和通过基类指针/引用调用派生类对象,是实现多态的基础。
虚基类:在派生类声明基类时加上 virtual 关键字,如 class B: virtual public A,A 就是虚基类。
解决的问题:菱形继承中,派生类从不同路径继承同一个基类时(如 D 继承 B 和 C,B 和 C 都继承 A),基类 A 的成员会在派生类 D 中产生两个副本,导致二义性。使用虚基类后,D 中只保留一份 A 的副本。
构造函数调用规则:如果虚基类定义了带参数的构造函数,那么所有直接或间接派生类都要在初始化表中列出虚基类构造函数。但编译系统只执行最终派生类对虚基类的构造函数调用,中间类的调用被忽略。
多态:同一函数调用在不同的对象上产生不同的行为。
静态多态(编译时多态):通过函数重载和运算符重载实现,在编译时就确定了调用哪个函数。优点是执行效率高,缺点是灵活性差。
动态多态(运行时多态):通过虚函数实现,在运行时才确定调用哪个函数。用基类指针指向派生类对象时,根据对象实际类型调用对应版本的函数。
实现条件:① 基类中声明虚函数(使用 virtual 关键字);② 派生类中重写(override)该虚函数;③ 通过基类指针或引用调用虚函数;④ 若使用纯虚函数(= 0),基类成为抽象类,不能实例化。
继承和派生的关系(课件5.1节):继承和派生是同一个过程的两个视角。继承是从子类的角度,描述子类获得基类特性的过程;派生是从基类的角度,描述从基类产生新类的过程。两者描述的实质是同一种机制——在已有类的基础上建立新类。
访问规则(课件5.4节):
① 无论哪种继承方式,基类的 private 成员在派生类中均不可直接访问。
② public 继承:基类 public 成员在派生类中保持 public,基类 protected 成员保持 protected。
③ protected 继承:基类 public 和 protected 成员在派生类中都变为 protected。
④ private 继承:基类 public 和 protected 成员在派生类中都变为 private。
⑤ 派生类可通过基类的 public/protected 成员函数间接访问基类的 private 成员(课件5.3-5.4节)。
💻 编程题 必考重点
每题 10 分,重点考察综合运用能力。
Box 类,包含长、宽、高私有成员,设计带参数的构造函数(使用初始化表),以及计算体积的成员函数。主函数创建两个长方体对象(12,25,30)和(15,30,21),输出它们的体积。// 参考代码 class Box { public: Box(int h, int w, int len): // 初始化表 height(h), width(w), length(len) {} int volume() { return height * width * length; } private: int height, width, length; }; int main() { Box box1(12, 25, 30); Box box2(15, 30, 21); cout << "box1体积=" << box1.volume() << endl; cout << "box2体积=" << box2.volume() << endl; return 0; }
Complex(私有数据成员 real, imag),重载 + 运算符实现复数加法(使用友元函数形式),重载 << 运算符实现复数输出。主函数中创建 c1(3,4)、c2(5,-10),计算 c3 = c1 + c2 并输出。// 参考代码 class Complex { friend Complex operator+(Complex &c1, Complex &c2); friend ostream& operator<<(ostream &out, Complex &c); public: Complex(double r = 0, double i = 0): real(r), imag(i) {} private: double real, imag; }; Complex operator+(Complex &c1, Complex &c2) { return Complex(c1.real + c2.real, c1.imag + c2.imag); } ostream& operator<<(ostream &out, Complex &c) { out << "(" << c.real << "," << c.imag << "i)"; return out; }
Student(学号、姓名),派生类 Student1(增加年龄),Student2(再增加成绩)。写出多层派生时各构造函数的写法。主函数创建 Student2 对象 stud(10010,"李明",17,89) 并输出全部数据。class Student { protected: int num; string name; public: Student(int n, string nam): num(n), name(nam) {} void display() { cout<<"num:"<" name:"< class Student1: public Student { protected: int age; public: Student1(int n, string nam, int a): Student(n, nam), age(a) {} }; class Student2: public Student1 { int score; public: // 只须调用直接基类 Student1 的构造函数 Student2(int n, string nam, int a, int s): Student1(n, nam, a), score(s) {} void show_all() { display(); cout<<"age:"< " score:"<
// 引用作为函数参数(形参是实参的别名) void swap(int &a, int &b) { int temp = a; a = b; b = temp; } // 调用时直接传变量(不用取地址) int i = 3, j = 5; swap(i, j); // i=5, j=3
Shape,包含纯虚函数 area()。派生类 Circle 实现面积计算。展示利用基类指针实现多态的用法。class Shape { public: virtual void area() = 0; // 纯虚函数 }; class Circle: public Shape { float r; public: Circle(float rr): r(rr) {} void area() { cout << 3.14 * r * r; } }; void fun(Shape *ptr) { ptr->area(); } // 动态关联 // 使用: Circle c(15); Shape *p = &c; fun(p); // 输出 Circle 的 area
template <typename T> T my_max(T a, T b) { return (a > b) ? a : b; } // 测试 cout << my_max(3, 7) << endl; // int → 7 cout << my_max(45.78, 93.6) << endl; // float → 93.6 cout << my_max('a', 'A') << endl; // char → 'a'
✅ 汇总答案
方便考前快速核对,标 红 为必考重点。
| 题号 | 答案 | 题号 | 答案 | 题号 | 答案 |
|---|---|---|---|---|---|
| 1 | B | 2 | A | 3 | C |
| 4 | D | 5 | 正确 | 6 | 错误 |
| 7 | 正确 | 8 | 正确 | 9 | <iostream> |
| 10 | endl | 11 | int | 12 | 引用 |
| 13 | 函数原型 | 14 | B | 15 | D |
| 16 | C | 17 | B | 18 | 正确 |
| 19 | 错误 | 20 | 封装 | 21 | 分号(;) |
| 22 | public | 23 | 消息 | 24 | inline |
| 25 | 错误 | 26 | B | 27 | A |
| 28 | C | 29 | C | 30 | 正确 |
| 31 | 错误 | 32 | 正确 | 33 | 错误 |
| 34 | 正确 | 35 | 类名 | 36 | ~ |
| 37 | 类模板 | 38 | friend | 39 | D |
| 40 | C | 41 | A | 42 | 错误 |
| 43 | 正确 | 44 | 错误 | 45 | operator |
| 46 | int | 47 | C | 48 | B |
| 49 | D | 50 | 正确 | 51 | 正确 |
| 52 | 正确 | 53 | 直接基类 | 54 | virtual |
| 55 | 友元函数 | 56 | 派生类 | 57 | 错误 |
| 58 | 正确 | 59 | C | 60 | D |
| 61 | B | 62 | 正确 | 63 | 正确 |
| 64 | 错误 | 65 | virtual | 66 | 0 |
| 67 | 抽象类 | 68 | 析构函数 | 69 | 正确 |
| 70 | 指针 | 71 | C | 72 | C |
| 73 | C | 74 | 定义 | ||
编程题参考代码和简答题参考答案已在题目下方给出,请理解后默写练习。
📖 基于课堂课件与教材出题 · 考前复习利器