简介:这份PDF面向准备全国计算机二级C++等级考试的考生,尤其是需要借助历年真题熟悉题型、检验复习效果的自学者与在校学生。内容以2007年二级笔试试卷为蓝本,整理出20道选择题并附参考答案,考点覆盖变量存储类型(auto、extern、register、static的默认规则)、类与对象的构造与拷贝构造、public继承下成员访问权限的变化、运算符重载的成员与非成员形式、函数模板与类模板的区分、C++流输入输出机制、friend与namespace等关键字辨析、switch与if控制结构、this指针的隐含使用,以及int *p=&k这类指针定义与等价语句序列的判定。资源包共1个PDF文件,约2.2MB,单文件结构便于打印或在手机上随时翻阅。目前已有1809人学习下载,适合用作章节自测与考前错题复盘,帮助读者按知识点定位薄弱环节,理解命题角度与常见干扰项的设置思路。
1. 计算机二级 C++ 笔试里最容易丢分的,往往不是指针
计算机二级 C++ 的笔试里,最容易丢分的不是指针,也不是递归,而是那些写代码时几乎不会这么写的语法细节。派生类不写继承方式,默认是私有继承;cout不是关键字,也不是类名,而是一个对象;运算符重载成成员函数时,一元运算符的参数表必须是空的。这类题在 70 分选择题里稳定占 20 分上下,靠语感答正确率不到一半,靠规则答半分钟一道。这份真题库收了多套笔试卷的选择题 35 道、填空题 15 空,题干和答案对得上原卷。下面按考什么、哪些必考、怎么答的顺序拆,适合已经能看懂 C++ 代码、但一做语法细节题就犹豫的考生。
2. 考点地图:70 分选择题的六块地盘与一套速判表
2.1 分数账:70 加 30 的卷面结构先算清楚
二级 C++ 笔试卷面就两块:选择题 35 题,每题 2 分,共 70 分;填空题 15 空,每空 2 分,共 30 分。从收录的两套卷子看,C++ 部分的选择题都从第 11 题开始,到第 35 题结束,前面 10 题属于公共基础知识;填空题的 C++ 部分从第 6 空开始。也就是说,真正考 C++ 语言的是选择题 25 题共 50 分,加上填空题 10 空共 20 分,合计 70 分左右,剩下 30 分是公共基础。
这 50 分选择题的分布很稳定,基本落在六块上:语言基础(关键字、标识符、类型等价、存储类型、指针声明)、类与对象(构造、拷贝构造、析构、this 指针、静态成员、const 成员函数)、继承与多态(访问权限、继承方式、虚函数、抽象类)、运算符重载、模板、流与格式化输出。读程序写结果那几道题不单独算一块,它们寄生在“类与对象”和“继承与多态”里,本质是同一批规则的应用题。
按两套卷子估一下权重:语言基础 10 到 14 分,类与对象 16 到 20 分,继承与多态 14 到 18 分,运算符重载、模板、流各 4 到 6 分。前三块加起来接近 45 分,是必须拿下的部分;后三块题量少但每年必到,属于“花两小时就能锁死”的性价比区。
2.2 六类真题速览:题干里出现这些词就往规则上靠
存储类型。“在函数中可以用 auto、extern、register、static 说明变量的存储类型,如果不说明,默认的存储类型是”。答案是auto。这四个关键字里,只有 auto 的语义就是“由编译器按默认规则处理”,另外三个都是在明确指定某种存储方式。看到“默认”两个字,直接找 auto。
关键字与标识符。“以下符号中不属于 C++ 关键字的是”,选项给 friend、namespace、continue、byte。答案是byte。friend 是友元声明,namespace 是命名空间,continue 是循环控制,byte 在 C++ 里从来不是关键字(C++17 起有std::byte,但那是标准库里的类型名,不是关键字)。另一道考标识符的题给 WHILE、user、_lvar、9stars,答案是9stars,因为标识符不能以数字开头。
类型等价。“以下各组量的声明中,含义一样的一组是”,答案是signed short int和short。判断方法只有一个:把修饰词叠全了比。signed short int等于short int等于short,三者完全等价;unsigned short和short差在有无符号,绝对不等价;unsigned long int和long也差在符号上;short int和int宽度不同。这道题的错误率一直很高,因为很多人在“short 和 short int 一样”这条上是对的,却顺手把 unsigned 那组也选上。
指针声明。“语句int *p=&k定义指针 p,与这个语句等效的语句序列是”,答案是int *p; p=&k;。关键在*是跟着类型走的声明符,不是解引用。写成int *p; *p=&k;就是拿一个没初始化的指针去解引用再取地址,语义完全变了,是典型的失分选项。
流对象。“在语句cout<<'A';中,cout 是”,答案是对象名。cout 是ostream类的一个预定义对象,不是类名、不是函数名、更不是关键字。同理 cin 是istream的对象。看到这四个选项,先把“关键字”和“类名”排掉。
文件流头文件。“要利用 C++ 流进行文件操作,必须在程序中包含的头文件是”,答案是fstream。iostream管标准输入输出,iomanip管格式控制符(setw、setfill 这些),strstream管字符串流。文件读写三个类 ifstream、ofstream、fstream 全在 fstream 里。
2.3 复习优先级:先拿这三块,再补后三块
| 模块 | 常见位置 | 分值区间 | 拿分难度 | 建议投入 |
|---|---|---|---|---|
| 类与对象 | 选择 12、22、27、28 附近 | 16 到 20 分 | 中,规则明确但要记牢 | 最高,先啃 |
| 继承与多态 | 选择 13、30、31、32、35 | 14 到 18 分 | 中偏高,权限表和输出顺序要背 | 次高 |
| 语言基础 | 选择 11、17、18、20 | 10 到 14 分 | 低,记住就不丢 | 快速过一遍 |
| 运算符重载 | 选择 14、24、33 | 4 到 6 分 | 中,四条红线一记就稳 | 集中两小时 |
| 模板 | 选择 15、25 | 4 到 6 分 | 低,规则少 | 半小时 |
| 流与格式化 | 选择 16、26、34 | 4 到 6 分 | 低,但 setw 的作用范围容易忘 | 半小时 |
这张表怎么用:如果你只剩一周,按“类与对象 → 继承与多态 → 运算符重载 → 语言基础 → 模板和流”的顺序过,前两块吃透就有 30 分以上的底。如果你时间充裕,把表里每一行对应的真题全部做一遍,再错题重做第二遍,正确率会明显抬起来。
2.4 客观题排除法:三个“绝对化”信号词
选项里出现“一定”“所有”“只能”,先按错误处理,除非你能举出反例证明它成立。真题里这类选项非常多:07 年第 12 题的 B 项“如果没有定义缺省的构造函数,编译器将一定生成一个缺省的构造函数”,只要考生定义过任何一个带参数的构造函数,编译器就不会再生成无参版本,这个“一定”直接把它判死;21 年第 14 题的 B 项“所有的运算符都可以通过重载而被赋予新的含义”,.、::、?:、sizeof这四个就不能重载,也是当场排除。
反过来,选项里出现“可以”“有的”“在一定条件下”,大概率是正确项。21 年第 15 题问关于模板的错误表述,A 项“调用模板函数时,在一定条件下可以省略模板实参”是真的,因为实参可以由传入参数的类型推导出来。这种措辞上的规律不能代替知识,但在两个选项之间犹豫时,它能帮你提高命中率。
提示:排除法只用来二选一,不要拿它替代规则记忆。选择题 50 分里,靠排除法能做对的不到一半,剩下全靠规则。
3. 类与对象高频考点:构造、拷贝、this 指针与静态成员
3.1 默认构造与拷贝构造:编译器什么时候替你写
这一块的规则只有四条,但每年都有人记反。第一条:类里没有定义任何构造函数时,编译器生成一个无参的默认构造函数。第二条:只要定义了任何一个构造函数(哪怕是无参的),编译器就不再生成默认构造函数。第三条:没有定义拷贝构造函数时,编译器生成一个拷贝构造函数。第四条:已经定义了构造函数和拷贝构造函数,编译器不再生成任何构造函数。
07 年第 12 题问哪个表述错误,正确选项是 B 项“如果没有定义缺省的构造函数,编译器将一定生成一个缺省的构造函数”。这句话错在“一定”上:如果类里已经写了一个带参数的构造函数,编译器不会补一个无参的,此时MyClass obj;这种写法会直接编译失败。C 项“如果没有定义构造函数,编译器将生成一个缺省的构造函数和一个拷贝构造函数”反而是对的。
21 年第 12 题换了个问法:“编译系统自动为一个类生成缺省构造函数的条件是”。答案是“该类没有定义任何构造函数”。注意干扰项“该类没有定义任何无参构造函数”和“该类没有定义任何有参构造函数”都不对——判据是“有没有定义构造”,不是“定义了哪种构造”。这两道题放在一起看,命题人的思路就很清楚了:他要的是你对“一旦自己写了,编译器就撒手”这句话的理解。
拷贝构造还有一个常考的细节:形参必须是本类对象的引用,写成MyClass(const MyClass x)是错的,因为传值会无限递归调用拷贝构造。真题里出现过MyClass(const MyClass& x)的写法,看到引用符号就知道这是标准形式。
3.2 初始化列表的顺序陷阱:一道题看清构造与析构的完整时序
下面这段代码是真题里出现过的变形,考点是成员对象的构造顺序到底听谁的:
#include <iostream> using namespace std; class Part{ public: Part(int x = 0) : val(x) { cout << val; } // 构造时输出 val ~Part() { cout << val; } // 析构时再输出一次 private: int val; }; class Whole{ public: // 初始化列表写的是 p2 在前、p1 在后 Whole(int x, int y, int z = 0) : p2(x), p1(y), val(z) { cout << val; } ~Whole() { cout << val; } private: Part p1, p2; // 但声明顺序是 p1 在前 int val; }; int main(){ Whole obj(1, 2, 3); return 0; }这段程序的输出是213312。
理清顺序就不难。构造阶段分三步:先按声明顺序构造成员对象,再执行本类构造函数体。声明顺序是p1, p2,所以 p1 先构造、p2 后构造。p1 对应初始化列表里的p1(y),y 是 2,输出 2;p2 对应p2(x),x 是 1,输出 1;最后进 Whole 的构造函数体,输出 val 即 3。构造阶段拼出213。
析构阶段完全反过来:先执行本类析构函数体,输出 3;再按声明的逆序析构成员对象,先 p2 输出 1,再 p1 输出 2,拼出312。合起来就是213312。
这里的关键认知是:初始化列表的书写顺序不影响构造顺序,编译器只认成员在类里的声明顺序。很多人看到p2(x), p1(y)就以为 p2 先,直接把答案选成123321,这正是命题人埋的坑。另外还要记住,基类永远排在成员对象之前,成员对象排在自身构造函数体之前;析构时严格倒序。
参数怎么读也要练。Whole obj(1, 2, 3)里 x=1、y=2、z=3,初始化列表把 x 给了 p2、y 给了 p1,所以 p1 拿到 2、p2 拿到 1。如果题干改成Whole obj(1, 2),z 取默认值 0,输出就变成210012。这类题不要背答案,每次重新按三步走一遍。
3.3 this 指针与静态成员函数:谁有、谁没有
07 年第 22 题给了一个头文件片段,里面有四个函数:全局函数int f1();、带 static 的全局函数static int f2();、类的普通成员函数int f3();、类的静态成员函数static int f4();。问哪些函数具有隐含的 this 指针。答案是f3。
判据一句话:只有非静态成员函数才有 this 指针。f1、f2 是全局函数,不属于任何对象,自然没有 this;f4 是静态成员函数,它属于类而不属于某个具体对象,调用时不需要对象,所以也没有 this。只有 f3 这种普通成员函数,编译器会偷偷给它加一个指向当前对象的指针参数。
这个知识点延伸出去还会考两点。一是静态成员函数里不能直接访问非静态成员变量,因为它没有 this,不知道访问的是哪个对象的成员。二是静态成员函数可以用类名::函数名()直接调用,也可以用对象调用,两种写法都对,21 年那道静态计数器题里obj.getCount()和MyClass::getCount()混着用就是这个道理。
3.4 静态成员变量:类外定义与计数器题的固定套路
#include <iostream> using namespace std; class MyClass{ public: MyClass() { ++count; } // 每构造一个对象,计数加 1 ~MyClass() { --count; } // 每析构一个对象,计数减 1 static int getCount() { return count; } private: static int count; // 声明,不分配内存 }; int MyClass::count = 0; // 类外定义并初始化,这一行不能少 int main(){ MyClass obj; cout << obj.getCount(); // 输出 1 MyClass* ptr = new MyClass; cout << MyClass::getCount(); // 输出 2 delete ptr; cout << MyClass::getCount(); // 输出 1 return 0; }输出结果是121。
三个输出点分别对应三种状态:栈上构造一个对象后计数为 1;再用 new 构造一个,计数累加到 2,注意静态成员被所有对象共享,所以不是每个对象各有一份;delete 掉堆上那个对象,析构函数把计数减回 1。
这段代码最容易错的地方不是逻辑,是int MyClass::count = 0;这一行。类里的static int count;只是声明,不分配存储空间,必须在类外再定义一次并初始化,否则链接阶段会报未定义符号。真题的选项里经常故意省略这一行,或者把它写成static int MyClass::count = 0;(多写了 static,错),考生如果只看主函数逻辑就会漏掉。
还有一个细节:getCount()是静态成员函数,返回的是共享的 count,所以三个输出点读的是同一个变量在不同时刻的值。如果题干把析构函数去掉,输出就会变成122,因为 delete 不会触发计数减一。做题时先确认“有没有析构函数”“有没有 delete”,再动笔算。
3.5 const 成员函数与 const 对象:语句级判断
21 年第 28 题给了一个类,里面void Set(int x){val=x;}是普通成员函数,void Print() const是常成员函数,主函数里定义const MyClass obj1(10);和MyClass obj2(20);,然后四条语句:obj1.Print()、obj2.Print()、obj1.Set(20)、obj2.Set(30)。问哪条错。答案是第三条。
规则很硬:const 对象只能调用 const 成员函数。obj1 是 const 对象,Print 带 const 修饰,可以调;Set 没有 const 修饰,编译器认为它可能修改对象状态,直接拒绝。obj2 是普通对象,两个函数都能调。所以错的是obj1.Set(20)。
反过来的方向也要记住:const 成员函数内部不能修改非静态成员变量,除非该变量加了 mutable。这条规则在选择题里常以“以下 const 成员函数定义哪个有语法错误”的形式出现,看到函数体里给成员变量赋值就圈出来。
注意:判断 const 相关题目时,先标出哪些对象是 const,再看被调用的函数有没有 const 后缀,两边对不上就是错。不要凭“这个函数看起来只是读数据”来判,编译器不看你函数体干了什么。
4. 继承与多态:权限表、构造顺序与虚函数的三个条件
4.1 三种继承方式的权限对照表
这张表必须背下来,考场上现推很容易乱:
| 基类中的访问级别 | public 继承后在派生类中 | protected 继承后 | private 继承后 |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | 不可直接访问 | 不可直接访问 | 不可直接访问 |
记忆方法:继承方式只会“降级”,不会“升级”。public 继承保持原样,protected 继承把 public 压成 protected,private 继承把所有能继承的都压成 private。基类的 private 成员无论怎么继承,派生类的成员函数都访问不到,只能通过基类提供的 public 或 protected 接口间接用。
07 年第 13 题问:“如果派生类以 public 方式继承基类,那么原基类的 protected 成员和 public 成员在派生类中的访问类型分别是”。按表查,protected 还是 protected,public 还是 public,答案是“protected 和 public”。这道题的干扰项是“protected 和 protected”,专抓那些把 public 继承当成“全部变 protected”的人。
同一批题里还有一道更综合的:基类 B 里void fun1(){}默认私有,protected: double var1;,public: void fun2(){};派生类 D 以 public 继承 B,自己加了个protected: void fun3(){}。问 D 的对象 obj 能调哪个。答案是obj.fun2()。fun1 在基类里是私有的,派生类对象访问不到;var1 是 protected,类外访问不到;fun3 在派生类里是 protected,类外同样访问不到。四个选项只有一个能过,考的其实就是那张表加“类外只能碰 public”。
4.2 默认继承方式是 private:一个字符不写就是坑
21 年第 31 题直接考这个:“定义派生类时,假设不使用关键字显式地规定采用何种继承方式,那么默认方式为”。答案是私有继承。
这条规则反直觉,因为很多人写代码时习惯写class D : public B,从没注意过不写会怎样。用 class 定义派生类,默认继承方式是 private;用 struct 定义,默认才是 public。这一个字符的差别,在选择题里就是 2 分。
与之配套的还有 21 年第 30 题:“对于通过公有继承定义的派生类,假设其成员函数可以直接访问基类的某个成员,说明该基类成员的访问权限是”。答案是“公有或保护”。因为派生类的成员函数在类内,能访问自己的 private、protected、public,也能访问基类的 public 和 protected,唯独不能访问基类的 private。
这里有个很容易混的点:派生类成员函数访问基类成员的权限,和派生类对象在类外访问成员的权限,是两套规则。前者看的是基类成员的原始访问级别(private 不行,其余都行),后者看的是继承之后降级的结果(只有 public 行)。题干里出现“派生类的成员函数”,按前者判;出现“派生类的对象”,按后者判。这一句话能救回好几道题。
4.3 虚函数与运行时多态:指针和引用才行,对象不行
#include <iostream> using namespace std; class Base{ public: void output() { cout << 1; } // 非虚函数,静态绑定 virtual void print() { cout << 'B'; } // 虚函数,动态绑定 }; class Derived : public Base{ public: void output() { cout << 2; } // 同名同参,但不是虚函数 void print() { cout << 'D'; } // 自动成为虚函数 }; int main(){ Base* ptr = new Derived; ptr->output(); // 输出 1 ptr->print(); // 输出 D delete ptr; return 0; }输出是1D。
ptr的静态类型是Base*,动态类型是Derived。调用非虚函数 output 时,编译器只看静态类型,绑到Base::output,输出 1。调用虚函数 print 时,运行时根据对象的实际类型查虚函数表,绑到Derived::print,输出 D。
这里要提醒一个常见误区:派生类里写void print()时没加 virtual,它仍然是虚函数。只要基类里声明为 virtual,派生类中同名同参数同返回类型的函数自动具有虚函数性质,加不加 virtual 都一样。这一点和“派生类里再写一遍 virtual 更清楚”并不冲突,但考试选项里如果说“派生类必须重新声明 virtual 才是虚函数”,那是错的。
再看一道把三种传参方式放在一起的题:
void fun1(Base* ptr) { ptr->show(); } void fun2(Base& ref) { ref.show(); } void fun3(Base b) { b.show(); } int main(){ Base b, *p = new Derived; Derived d; fun1(p); // 输出 D fun2(b); // 输出 b fun3(d); // 输出 b return 0; }假设Base::show()是虚函数,Derived::show()输出 'D',Base::show()输出 'b'。第一个调用:p 指向 Derived 对象,指针传递不切片,动态绑定到 Derived,输出 D。第二个调用:传的是 Base 对象 b,引用绑定到 Base 对象本身,虚函数表是 Base 的,输出 b。第三个调用:按值传递,Derived 对象被切片成 Base 子对象,进函数时已经是个纯 Base,输出 b。合起来Dbb。
这道题把所有陷阱一次踩全:指针和引用能实现多态,按值传参会切片。21 年第 23 题问“与实现运行时多态性无关的是”,答案是“重载函数”。运行时多态靠的是虚函数加基类指针或引用;函数重载是编译期根据实参类型选函数,属于静态多态,两回事。
4.4 抽象类与纯虚函数:选择和填空都考
纯虚函数的写法是virtual 返回类型 函数名(参数表) = 0;。含有纯虚函数的类叫抽象类,抽象类不能实例化对象,只能作为基类被继承,派生类必须把全部纯虚函数实现掉才能创建对象。
21 年第 35 题问“在一个抽象类中,一定包含有”,答案是纯虚函数。这题容易错选“虚函数”,因为纯虚函数也是虚函数的一种,但反过来不成立——一个类如果只有普通虚函数,没有纯虚函数,它仍然是具体类,可以实例化。判据只看有没有= 0。
填空题里常见的两个空:一是补纯虚函数声明,题干给出_____让你填完整,答案形如virtual void display() = 0;,注意= 0不能漏,virtual 不能漏;二是补基类成员函数的类外定义,题干里基类声明了void fun();,派生类要调用,空里填void Base::fun(){},注意类名限定符Base::必须写,返回类型和参数表要跟声明完全一致。
还有一种填空考的是访问控制配合虚函数:题干给出基类析构函数不是虚函数,派生类对象用基类指针 delete 时只调基类析构,导致资源泄漏。这类题在二级里出现频率不高,但一旦出现就是送命题,记住“基类析构要写成 virtual”这一条即可。
4.5 构造与析构在继承链上的顺序
21 年第 32 题问“建立一个有成员对象的派生类对象时,各构造函数体的执行次序”。答案是“基类、成员对象类、派生类”。
把这条和 3.2 那道题合起来,就是完整的时序规则:构造时,先基类(按继承声明顺序,多继承时从左到右),再成员对象(按类内声明顺序),最后自己的构造函数体;析构时严格反序,先自己的析构函数体,再成员对象逆序,最后基类。
07 年有一道填空题专门考这个:基类 A 的析构函数输出 "aa",派生类 B 的析构函数输出 "bb",主函数里B* p = new B; delete p;,要求输出 "bbaa"。空里要填的是基类的析构函数定义~A(){cout<<"aa";}。因为 delete 时先执行 B 的析构(bb),再自动调用 A 的析构(aa),顺序天然就是 bbaa,不需要在 B 的析构里手动调。这一点经常有人想复杂,跑去 B 的析构函数里写~A();,那是语法错误。
5. 易错点:五类年年出、年年有人错的题
5.1 运算符重载的参数个数:成员函数要减一个
错在哪。看到Value operator-(Value, Value);就以为它是合法的重载,或者看到成员函数版本带一个参数就以为是一元运算符。
为什么错。成员函数有一根隐含的 this 指针,它占掉了第一个操作数的位置。所以重载为成员函数时,一元运算符参数表为空,二元运算符参数表只有一个参数。重载为非成员函数时没有 this,一元运算符一个参数,二元运算符两个参数。21 年第 24 题问“肯定不属于类 Value 的成员函数的是”,正确选项是Value operator-(Value, Value);,两个参数,如果是成员函数就等于三元运算了,C++ 里没有这种东西。
怎么答对。拿到题先数参数个数,再看是不是成员函数。成员函数:0 个参数是一元,1 个参数是二元,2 个参数直接判死。非成员函数:1 个参数是一元,2 个参数是二元。另外记住一条硬规则:重载运算符的至少一个操作数必须是类类型或枚举类型,所以myclass operator*(double, double);这种两个操作数都是内置类型的声明是非法的,因为不能给内置类型重载运算符。
5.2 初始化列表的顺序被当成构造顺序
错在哪。看到: p2(x), p1(y)就按 p2、p1 的顺序算输出。
为什么错。成员对象的构造顺序只由它们在类中的声明顺序决定,初始化列表的书写顺序不参与。编译器对初始化列表的求值顺序也跟声明顺序一致,很多编译器对写反的顺序还会给警告。
怎么答对。做这类题先在草稿纸上把成员按声明顺序从上往下抄一遍,再把初始化列表里的对应关系一个个标到抄好的序列上,最后才动笔算输出。析构时把这张纸倒过来读。不要靠记忆背答案,题干里换个参数顺序,答案就全变了。
5.3 默认继承方式与访问权限混着记
错在哪。认为不写继承方式就是 public,或者认为 public 继承之后基类的 protected 会变成 public。
为什么错。class 定义派生类时默认是 private 继承,struct 定义时默认才是 public 继承。继承方式只降不升:public 继承保持原级别,protected 继承把 public 降成 protected,private 继承把所有可继承成员降成 private。
怎么答对。考前把 4.1 那张三行三列的表默写一遍,考场上凭表查。遇到“派生类成员函数能访问基类什么”的问题,切换到另一套规则:基类 private 不行,其余都行。题干主语是“对象”还是“成员函数”,决定用哪套规则,这一句判断比背十条结论都管用。
5.4 编译不过就归因于继承方式
错在哪。题干说“派生类成员函数中调用基类的void f();无法通过编译”,很多考生第一反应选“派生类的继承方式为私有”。
为什么错。私有继承只是把基类的 public 和 protected 成员在派生类里降级为 private,派生类自己的成员函数仍然能访问这些 private 成员。私有继承不影响派生类内部调用基类函数,它影响的是派生类对象在类外的访问,以及再往下继承。
怎么答对。派生类成员函数调不到基类函数,只有一种可能:这个函数在基类里就是 private。按这个思路排选项,如果选项里同时有“f() 是基类的私有成员”和“继承方式为私有”,优先选前者。反过来,如果题干说的是“派生类对象在 main 里调用不了基类的 public 函数”,那才轮到继承方式背锅。
5.5 setw 只管一次,setfill 一直管
错在哪。认为cout << setw(10) << setfill('*') << 1234会输出 10 个星号加 1234,或者认为 setw 设置一次之后对后面所有输出都生效。
为什么错。setw 是“一次性”的,只对紧随其后的那一个输出项生效,输出完就恢复默认;setfill 是“持久”的,设置后一直有效,直到你再次修改。上式的正确输出是 6 个星号加 1234,共 10 个字符宽,因为 1234 占 4 位,剩下 6 位用星号补在左边(默认右对齐)。
怎么答对。数三样东西:宽度、填充字符、数字本身的位数。宽度减位数就是填充字符的个数。还要注意 setw 和 setfill 的书写先后不影响结果,因为填充字符是在真正输出那一刻才去查的,写成setfill('*') << setw(10)结果一样。另外记住 ofstream 定义对象打开文件时默认方式是ios_base::out,也就是只写;要又读又写得显式写ios_base::in | ios_base::out。
6. 答题技巧:读程序题的三步法,和四类必考押题
读程序写结果那几道题,我用的是固定三步,几乎不出错。第一步,先在草稿纸左边竖着列三行:
本文还有配套的精品资源,点击获取