写在最前
在我的上一篇博文:“公共基础知识篇(一)”中,根据历年真题及最新大纲模拟题,个人整理了一些公共基础知识部分的易错题。本文继续介绍C++二级考试选择题部分的“重头戏”,分数值占到选择题总分75%的C++知识部分。
文章目录
重载、重载运算符
双目运算符“=、( )、[ ]、->”不能重载为类的友元函数。
C++中,赋值运算符=、下标运算符[]、调用运算符()、成员访问指针运算符->必须重载为成员函数。
不能重载的运算符只有5个:’.’、’.*’、’::’、‘sizeof’、’?’。
函数不能仅仅只基于不同的返回类型而实现重载。
析构函数没有返回值,没有形参,所以析构函数不能重载。(同样构造函数也没有返回值)。
重载运算符的函数不能有默认的参数,否则就改变了运算符的参数个数。
下列关于重载运算符的说法正确的是()。
A)运算符 :: 不能被重载,运算符 . 必须作为类成员重载
B)运算符 [ ] 不能被重载,运算符 = 必须作为类成员重载
C)运算符 * 不能被重载,运算符 ( ) 必须作为类成员重载
D)运算符 . 不能被重载,运算符 [ ] 必须作为类成员重载
【解析】本题考查运算符重载,不能重载的运算符只有5个:’.’、’.*’、’::’、‘sizeof’、’?:’。C++规定有的运算符(如赋值运算符、下标运算符、函数调用运算符)必须定义为类的成员函数,只有D选项正确。
有如下定义:
class MyClass{
public:
【 】
private:
int data;
}
若要为MyClass类重载流输入运算符“>>”,使得程序中可以“cin>>obj;”的形式改变MyClass类的对象obj中的数据成员data的值,则【 】处的声明语句应为()。
A)friend istream& operator >>(istream& is, MyClass& a);
B)friend istream& operator >>(istream& is, MyClass a);
C)istream& operator >>(istream& is, MyClass& a);
D)istream& operator >>(istream& is, MyClass a);
【解析】本题答案为A。
类似“<<”和“>>”这样的运算符只能重载为类外的非成员函数,所以在类内声明时要加上friend表示这是个友元函数;
为什么类似“<<”和“>>”这样的运算符只能重载为类外的非成员函数?
因为:运算符的左操作数不是我们自定义的类对象(比如标准库里的类对象或者实数等等),那么重载运算符函数就不能定义在类内。
下面是重载为非成员函数的运算符的函数声明,其中错误的是()。
A)Fraction opreator +(Fraction, Fraction);
B)Fraction opreator -(Fraction);
C)Fraction& opreator =(Fraction&, Fraction);
D)Fraction& opreator +=(Fraction&, Fraction);
【解析】
运算符重载为类的成员函数,函数参数个数=原操作数个数 - 1;
运算符重载为非成员函数,函数的参数个数=原操作数个数(后置++,–除外);
B选项,当-表示的是负号,则成立;
C选项,C++强制规定,重载赋值运算符函数,只能是类的非静态成员函数。
通过运算符重载,可以改变运算符原有的()。
A)优先级
B)结合性
C)操作数类型
D)操作数个数
【解析】重载不能改变运算符运算对象的个数;不能改变运算符的优先级别;不能改变运算符的结合性。
若要在Viz类中将*重载为一元运算符,下列重载函数声明中肯定有错的是()。
A)Viz opreator *();
B)Viz operator *(Viz);
C)int operator *(Viz); //int表示函数返回的是int型,不是错的!
D)Viz operator *(Viz, Viz);
【解析】将*重载为一元运算符,所以只有一个操作数,而D选项有两个操作数,所以D错误。
下面是重载为非成员函数的运算符函数原型,其中错误的是()。
A)Fraction operator +(Fraction);
B)Fraction operator -(Fraction);
C)Fraction operator *(Fraction);
D)Fraction operator /(Fraction);
【解析】将*重载为一元运算符,所以只有一个操作数,而D选项有两个操作数,所以D错误。
设c1和c2是类MyClass的对象,若将前缀运算符“–”和运算符“/”作为类MyClass的友元函数重载,则表达式–c1/c2等价于()。
A)operator/(c1.operator–(), c2)
B)operator/(operator–(c1),c2)
C)c1.operator–().operator/(c2)
D)c2.operator/(operator–(c1))
【解析】
友元函数不是类的成员函数,所以友元函数的调用不需要使用类对象;
“–”优先级高于“/”!所以先执行“–”运算符重载函数,之后执行“/”运算符重载函数;
如果"–"和“/”重载为类的成员函数,则C选项正确。
重载类型转换运算符
类中重载类型转换运算符的一般声明 :operator T() const;
若要对类Value中重载的类型转换运算符long进行声明,下列选项中正确的是()。
A)operator long() const;
B)operator long(Value) const;
C)long operator long();
D)long operator long(Value);
【解析】
本题考查类型转换函数,其一般形式如下:operator 类型名(){实现转换的语句};
在函数名前面不能指定函数类型,函数没有参数,所以A选项正确。
有如下类定义:
class MyClass{
public:
MyClass(double d=0.0): val(d) { }
___________ //类型转换运算符double的定义
private:
double val;
};
若要使语句序列
MyClass x(2.1);
cout<<double(x);
能够正常运行,横线处的语句应为()。
A)operator double() const {return val;}
B)friend operator double() const {return val;}
C)double operator() const {return val;}
D)friend double operator() const {return val;}
【解析】题目需要定义类型转换运算符double,类型转换运算符是一种特殊的类成员函数,它定义将类类型的值转变为其他类型值,由于转换函数必须是成员函数,选项B、D错误;另外转换函数不能指定返回类型,并且形参列表必须为空,选项C错误;所以double类型转换运算符的定义为:operator double() const{return val};答案为A。
常对象、常数据成员、常成员函数
常数据成员
◆ 常数据成员必须进行初始化,并且不能被更新。
◆ 常数据成员不能在声明时赋初始值(普通数据成员也是),常数据成员必须在构造函数初始化列表进行初始化;普通数据成员在初始化列表和函数体中初始化均可。
◆ PS:类的成员对象若要传入参数初始化,则必须在构造函数初始化列表进行;(成员对象:当一个类的成员是另一个类的对象时,这个对象就叫成员对象。)
常对象
◆ ⭐常对象可以调用常成员函数,不能调用非const成员函数;非const对象,可以调用普通成员函数和常成员函数。
◆ 常对象的成员函数不一定都是常成员函数;同样的常对象的数据成员不一定都是常数据成员。
◆ 常对象一旦初始化,常对象的数据成员便不允许修改,而不是说常对象的数据成员都是常数据成员。
◆ PS:定义常对象有两种方法,1. Point const a; 2. const Point a;(同样的,定义变量或指针时,const放前放后意义一样,如:1. const double a; double const a; 2. const int *p; int const *p; 但是定义指针常量时,只能用 int * const p;)
常成员函数
常成员函数
◆ 常成员函数不更新对象的数据成员。
◆ 常成员函数的const关键字可以被用于参与对重载函数的区分。
◆ ⭐通常非const成员函数需要定义一个const版本的重载函数,以方便定义常对象后调用常成员函数。
◈ 如果常对象调用的常成员函数返回的是指向当前对象的指针(或返回的是当前对象),那么此常成员函数的声明的返回类型要加const,例如:
◊ 成员函数返回指向当前对象的指针
const *Point fun1(); //非const成员函数的类内声明;
const *Point fun1() const; //习惯上要再声明一个常成员函数作重载函数,注意到此函数声明有两个const;
◊ 成员函数返回指向当前对象
const Point fun1(); //非const成员函数的类内声明;
const Point fun1() const; //习惯上要再声明一个常成员函数作重载函数,注意到此函数声明有两个const;
◊ ⭐注意,如果一个类中声明以下4个重载函数:
① Point fun1();
② const Point fun1();
③ Point fun1() const;
④ const Point fun1() const;
【解析】①和②是冲突的,因为无法区分仅按返回类型区分的重载函数;③和④是冲突的,也是因为无法区分仅按返回类型区分的重载函数。
所以正确的重载函数搭配有3种:
◊ ①和③搭配:
Point fun1(); //函数返回非const对象
Point fun1() const; //函数返回非const对象
[解析]适用于定义常对象后调用常成员函数,常成员函数返回类型是非const的Point类对象。
◊ ①和④搭配(这里把返回类型改为指针,因为常用):
Point *fun1() {return this; }; //函数返回指向本对象的指针
const Point *fun1() const { return this; };//函数返回指向本常对象的指针,第一个const说明返回的是指向常对象的指针,第二个const说明此函数是常函数
[解析]适用于定义常对象后调用常成员函数,常成员函数返回类型是常Point类对象(如return *this;)。
◊ ②和④搭配:
const Point fun1(); //函数返回常对象
const Point fun1() const; //函数返回常对象
[解析]适用于定义常对象后调用常成员函数,常成员函数返回类型是常Point类对象。
◊ ②和③搭配:
const Point fun1();
Point fun1() const;
[解析]虽然搭配合法,但是似乎不存在这种搭配。
内联函数
⭐下列关于内联函数的叙述中,错误的是()。
A)内联函数的定义必须出现在内联函数第一次被调用之前
B)内联函数主要解决程序的运行效率问题
C)类体中定义的函数都是内联函数
D)内联函数不能有参数
【解析】内联函数的函数定义必须出现在内联函数第一次被调用之前;内联函数可以避免函数频繁调用时的开销,提高程序运行效率;在类定义体内部定义的成员函数,编译器都将其视为内联函数(包括构造函数);A、B、C正确;内联函数也可以有参数,D错误,答案为D。
在C++中,用来取代C中的预处理宏函数的是()。
A)重载函数
B)友元函数
C)递归函数
D)内联函数
【解析】内联函数被发明出来就是为了取代C中的宏,故选D。(联想到内联函数与一般函数不同之处就在于函数调用的预处理)
有如下类及函数的定义:
class Wow{
int k;
public:
Wow(int n=0): k(n) { }
int incre() { return ++k;}
int decre();
void show() const;
};
int Wow::decre() { return --k; }
inline void display(Wow w) { w.show(); }
void Wow::show() const { cout<<k; }
在上面所定义的函数中,内联函数的个数是()。
A)1
B)2
C)3
D)4
【解析】类定义体内部定义的函数,编译器都默认为内联函数(包括构造函数!!),类定义体外部定义的函数,使用关键字inline修饰的函数为内联函数,所以内联函数有:Wow(int n=0)、incre()、display(Wow w),答案为C。
有如下定义:
class Box{
public:
double GetLength() {return length;}
double GetWidth();
double GetHeight();
private:
double length, width, height;
};
inline double Box::GetWidth() {return width;}
double Box::GetHeight() {return height;}
在成员函数GetLenth、GetWidth和GetHeight中,内联函数有()。
A&