91-100

注:以下问题的部分解析并非全部是自己原创,只是为了便于以后复习,直接粘贴总结的答案,主要来源是七月在线中的解析部分。https://www.julyedu.com/question/selectAnalyze/kp_id/4/cate/C

1、 以下哪些做法是正确的( )

A 构造函数声明为虚函数
B 派生关系中的基类析构函数声明为虚函数
C 构造函数调用虚函数
D 析构函数调用虚函数

解释:选B

虚函数不能是内联函数,构造函数不能是虚函数。
A选项,构造函数不能声明为虚函数,虚函数对应一个vptr(虚函数表指针),可是vptr其实是存储在对象的内存空间的。如果构造函数是虚的,就需要通过 vptr来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vptr,所以构造函数不能是虚函数。
B选项,析构函数可以声明为虚函数,而且有时是必须声明为虚函数,是因为删除指向派生类的基类指针的时候,如果基类析构函数不是虚函数,派生类的析构函数将不会被执行,其直接后果是内存泄漏。
C选项,在构造函数里面调用虚函数,编译不会报错,但是最好不要这样做。在调用构造函数时,类里面的变量可能还被未初始化,虚函数这时可能会访问内存中未知的区域而产生错误,所以最好不要在构造函数里调用虚函数。
D选项,在析构函数中调用虚函数,最好不要这样做。对象的析构过程是先析构派生类,然后析构基类;当在基类的析构函数调用虚函数,往往其派生类部分已经被析构,所以也不会呈现出多态。而如果在基类的析构函数中调用纯虚函数,编译器会报错(一般会报纯虚函数名无法解析等错误)。

2、 有如下几个类和函数定义,选项中描述正确的是( )

class A
{
public:
virtual void foo() { }
};

class B
{
public:
virtual void foo() { }
};

class C : public A , public B
{
public:
virtual void foo() { }
};

void bar1(A *pa)
{
B *pc = dynamic_cast(pa);
}

void bar2(A *pa)
{
B *pc = static_cast(pa);
}

void bar3()
{
C c;
A *pa = &c;
B *pb = static_cast(static_cast(pa));
}
A bar1无法通过编译
B bar2无法通过编译
C bar3无法通过编译
D bar1可以正常运行,但是采用了错误的cast方法

解释:选B

static_cast和dynamic_cast都是用于强制类型转换。dynamic_cast是在运行时遍历继承树,所以,在编译时不会报错。但是因为A和B无关,所以运行时报错,那么A和D都是错误的。static_cast:编译器隐式执行的任何类型转换都可由它显式完成。
其中对于:
(1)基本类型。如可以将int转换为double(编译器会执行隐式转换),但是不能将int用它转换到double(没有此隐式转换)。
(2)对于用户自定义类型,如果两个类无关,则会编译出错(所以B正确),如果存在继承关系,则可以在基类和派生类之间进行任何转型,在编译期间不会出错。所以bar3可以通过编译(C选项是错误的)。

3、 在Intel CPU上,以下多线程对int型变量x的操作,哪个是原子操作,假定变量的地址都是对齐的( )

A x = y
B x++
C ++x
D x = 1

解释:选D

原子操作是不可被中断的一个或一系列操作,原子操作在执行完毕之前不会被任何其它任务或事件中断。在单处理器系统中,能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间;如果一个操作包含多个cpu指令则不是原子操作。将ABCD四个选项进行反汇编,可以得出:x = y是先将内存中的y读到寄存器中,然后再将寄存器值赋给x,分为2步操作;x++是先将内存中的x读到寄存器中,然后进行+1操作,最后再将寄存器值赋给x,分为3步操作;++x也是先将内存中的x读到寄存器中,然后进行+1操作,最后再将寄存器值赋给x,分为3步操作;x=1是直接对内存进行赋值操作,是单步操作。因此,四个操作中,只有x=1是单条指令完成的,其他都是多条指令完成,因此ABC不是原子操作,D是原子操作。

4、 一般情况下,下面哪些操作不会执行失败( )

class A
{
public:
string a;
void f1()
{
printf(“Hello World”);
}
void f2()
{
a = “Hello World”;
printf("%s",a.c_str());
}
virtual void f3()
{
printf(“Hello World”);
}
virtual void f4()
{
a = “Hello World”;
printf("%s",a.c_str());
}
};
A A *aptr = NULL; aptr->f1();
B A *aptr = NULL; aptr->f2();
C A *aptr = NULL; aptr->f3();
D A *aptr = NULL; aptr->f4();

解释:选A

本题考查了成员函数和成员变量的存储方式:成员函数的代码存储在对象空间之外,成员函数是不属于对象的,而成员变量是属于对象的。因为f1()函数没有使用任何成员变量,所以A正确。在B中f2()函数使用了成员变量a,而成员变量存在于对象中,但是aptr为NULL,无法使用成员变量a,所以B执行失败。C选项中,虚函数需要有虚表指针,虚表指针只存在于对象中,所以C执行失败。D选项结合了B和C中的错误。

5、 以下哪个说法正确( )

int func()
{
char b[2]={0};
strcpy(b,“aaa”);
}
A Debug版崩溃,Release版正常
B Debug版正常,Release版崩溃
C Debug版崩溃,Release版崩溃
D Debug版正常,Release版正常

解释:选A

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。Debug 和 Release 并没有本质的区别,他们只是VC预定义提供的两组编译选项的集合,编译器只是按照预定的选项行动。func函数中数组b越界。Debug 版本会打开编译调试代码开关(assert函数会被编译) ,Release版本关闭条件编译调试代码开关(即不编译assert函数)。因此在Debug版本中会报错,而release版本不会报错。

6、 有如下C++代码,输出结果为( )

#include < iostream >
using namespace std;
#define S(a,b) a*b
int main(int argc, char * argv[]){
int s = S(1+2,3+4);
cout << s << endl;
return 0;
}
A 10
B 11
C 20
D 21

解释:选B

S(1+2,3+4) ==> 1+2*3+4=11

7、 以下程序的输出结果是( )

main()
{
int i,j,k,a = 3,b = 2;
i = (–a==b++)?–a:++b;
j = a++;k=b;
printf(“i=%d,j=%d,k=%d\n”,i,j,k);
}
A i=2,j=1,k=3
B i=1,j=1,k=2
C i=4,j=2,k=4
D i=1,j=1,k=3

解释:选D

i = ( --a ==b++)?–a:++b; == > a = 2, a == 2(真),b = 3 , a = 1 , i = 1
j = a++ == > j = a = 1, a = 2
k=b == > k = 3

8、已知(int : 4个字节,float : 4个字节,double : 8个字节)

struct
{
int i;
float j;
double k;
}test1;

union
{
int i;
float j;
double k;
}test2;
请问sizeof ( test1 ),sizeof ( test2 )的值分别为(不考虑对齐问题)( )
A 16,16
B 16,8
C 8,16
D 8,8

解释:选B

由于不考虑对齐问题,也就是说所有的对齐都按照1的整数倍对齐。因此,sizeof(test1)的值为4+4+8=16. 由于union类型的各个成员变量是以同一地址开始存放,因此union类型实际占用的存储空间为其最长的成员变量所占的存储空间,因此,sizeof(test2)的值为8.

9、 a,b为int型传入参数,下面四个选项中,不可以实现a,b值互换的是( )

A void swap(int &a, int &b) {int tmp = 0; tmp = b; b = a; a = tmp;}
B void swap(int &a, int &b) {a = a+b; b = a-b; a = a -b;}
C void swap(int a, int b) {int tmp = 0; tmp = b; b = a; a = tmp;}
D void swap(int &a, int &b){a = a+b-(b=a); }

解释:选C

选项A,函数定义了a和b为实参的引用,相当于直接在原变量上进行操作,函数中通过tmp变量实现a和b值的互换。
选项B,函数定义了a和b为实参的引用,函数中a首先赋为a和b的和,b等于和减去自身,即此时b为原a的值,a等于和减去b,即得到原b的值。
选项C,函数定义了a和b为实参的两个副本,此时仅进行了副本值的交换。
选项D,函数定义了a和b为实参的引用,表达式中首先计算括号的内容,即b赋值为a,此时表达式变为a=a+b-a,而前两项a和b的值事先压到操作数栈中,故前两项的和为原两个变量的和,和减去a得到b,即a等于原b的值,实现了值的互换(有些版本中这样是不能实现互换的)。

10、 下列关于C语言的描述正确的是( )

A C语言的基本单位是语句
B C语言的三种结构的顺序、选择、循环
C C语言是高级语言程序,因此输入后即可执行
D C语言从第一条可执行语句开始执行

解释:选B

C语言的基本单位是函数;C程序需要经过编译和链接才能执行;C语言从main函数开始执行。

发布了31 篇原创文章 · 获赞 4 · 访问量 2451

猜你喜欢

转载自blog.csdn.net/weixin_44412429/article/details/95311686
今日推荐