您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业财务 > C++经典笔试题(附答案)
•1•8:下列多重继承时的二义性问题如何解决?classA{//类A的定义public:voidprint(){coutHello,thisisAendl;}};classB{//类B的定义public:voidprint(){coutHello,thisisBendl;}};classC:publicA,publicB{//类C由类A和类B共同派生而来public:voiddisp(){print();}//编译器无法决定采用A类中定义的版本还是B类中的版本};解答:若两个基类中具有同名的数据成员或成员函数,应使用成员名限定来消除二义性,如:voiddisp(){A::print();//加成员名限定A::}但更好的办法是在类C中也定义一个同名print函数,根据需要调用A::print()还是B::print(),从而实现对基类同名函数的隐藏9:下列公共基类导致的二义性如何解决?classA{//公共基类public://public成员列表voidprint(){coutthisisxinA:endl;}classB:publicA{};classC:publicA{};classD:publicB,publicC{};voidmain(){.2•Dd;//声明一个D类对象dA*pa=(A*)&d;//上行转换产生二义性d.print();//print()具有二义性,系统不知道是调用B类的还是C类的print()函数}注意:把子类的指针或引用转换成基类指针或引用是上行转换,把基类指针或引用转换成子类指针或引用是下行转换。解答:1)main函数中语句“d.print();”编译错误,可改为以下的一种:d.B::print();d.C::print();若改为“d.A::print();”又会如何呢?由于d对象中有两个A类对象,故编译会报“基类A不明确”。2)语句“A*pa=(A*)&d;”产生的二义性是由于d中含有两个基类对象A,隐式转换时不知道让pa指向哪个子对象,从而出错。可改为以下的一种:A*pa=(A*)(B*)&d;//上行转换A*pa=(A*)(C*)&d;//上行转换事实上,使用关键字virtual将共同基类A声明为虚基类,可有效解决上述问题。10:下面哪种情况下,B不能隐式转换为A()?(2011•腾讯)A.classB:publicA{}B.classA:publicB{}C.classB{operatorA();}D.classA{A(constB&);}解答:B。因为子类包含了父类部分,所以子类可以转换为父类,但是相反,父类没有子类额外定义的部分,所以不能转换为子类,故A正确,而B错误。非C++内建型别A和B,在以下几种情况下B能隐式转化为A。1)B公有继承自A,可以是间接继承的。classB:publicA{};此时若有“Aa;Bb;”,则“a=b;”合法。2)B中有类型转换函数。classB{.3•operatorA();};此时若有“Aa;Bb;”,则“a=b;”合法。3)A实现了非explicit的参数为B(可以有其他带默认值的参数)的构造函数classA{A(constB&);};此时若有“Aa;Bb;”,则“a=b;”合法。11:调用一成员函数时,使用动态联编的情况是()。(2011•淘宝)A.通过对象调用一虚函数B.通过指针或引用调用一虚函数C.通过对象调用静态函数D.通过指针或引用调用一静态函数解答:B。结合一段示例代码来看虚函数的作用,以帮助大家理解多态的意义所在。例2:下述代码的输出结果是什么?classbase{public:virtualvoiddisp(){couthello,base1endl;}voiddisp2(){couthello,base2endl;}};classchild1:publicbase{public:voiddisp(){couthello,child1endl;}voiddisp2(){couthello,child2endl;}voidmain(){base*base=NULL;child1objchild1;base=&objchildl;base-disp();base-disp2();解答:输出:hello,childl.4•hello,base2从上述代码可见,通过指针访问函数时:1)不加virtual时,具体调用哪个版本的函数只取决于指针本身的类型,和指针所指对象的类型无关。2)而加virtual时,具体调用哪个版本的函数不再取决于指针本身的类型,而是取决于指针所指对象的类型。13:构造函数为什么不能为虚函数?解答:假设有如下代码:classA{A(){}};classB:publicA{B():A(){}};则构造B类的对象时:1.根据继承的性质,构造函数执行顺序是:A()B()2.根据虚函数的性质,如果A的构造函数为虚函数,且B类也给出了构造函数,则应该只执行B类的构造函数,不再执行A类的构造函数。这样A就不能构造了。3.这样1和2就发生了矛盾。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。14:哪些函数不能为虚函数?解答:常见的不能声明为虚函数的有:普通函数(非成员函数)、静态成员函intmain(){Bb;B*pb=&b;}.5•数、构造函数、友元函数,而内联成员函数、赋值操作符重载函数即使声明为虚函数也无意义。1)为什么C++不支持普通函数为虚函数?普通函数(非成员函数)只能被overload(重载),不能被override(覆盖),声明为虚函数也没有什么意义,因此编译器会在编译时绑定函数。为什么C++不支持构造函数为虚函数?上例己经给出了答案。2)为什么C++不支持静态成员函数为虚函数?静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,它不归某个具体对象所有,所以它没有要动态绑定的必要性。3)为什么C++不支持友元函数为虚函数?因为C++不支持友元函数的继承,没有实现为虚函数的必要。以下两种函数被声明为虚函数时,虽然编译器不会报错,但是毫无意义。内联函数:内联函数是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后,对象能够准确地执行自己的动作,这是不可能统一的。即使虚函数被声明为内联函数,编译器遇到这种情况根本不会把这样的函数内联展开,而是当作普通函数来处理。赋值运算符:虽然可以在基类中将成员函数operator定义为虚函数,但这样做没有意义。赋值操作符重载函数要求形参与类本身类型相同,故基类中的赋值操作符形参类型为基类类型,即使声明为虚函数,也不能作为子类的赋值操作符。15:以下描述正确的是()。(2011•盛大游戏)A.虚函数是可以内联的,可以减少函数调用的开销提高效率B.类里面可以同时存在函数名和参数都一样的虚函数和静态函数C.父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数D•以上都不对解答:C。C中delete子类对象指针会调用父类的析构函数(即使子类的析构函数不是虚的,对子类对象指针调用析构函数,也会调用父类的析构函数),但若delete父类对象指针却不会调用子类的析构函数(因为父类的析构.6•函数不是虚函数,不执行动态绑定)。16:以下代码的输出结果是()。(2012•小米)classB{public:B(){cout”Bconstructor,”;s=“B”;}voidf(){couts;}peivate:strings;};classD:publicB{public:D():B(){coutDconstructor,;s=“D”;}voidf(){couts;}private:strings;};intmain(void){B*b=newD();b-f();((D*)b)-f();deleteb;return0;}解答:输出结果是:Bconstructor,Dconstructor,BD若在类B中的函数f前加上virtual关键字,则输出结果为:Bconstructor,Dconstructor,DD.7•可见若函数不是虚函数,则不是动态绑定。17:下列代码的输出结果是什么?(2012•网易)classA{public:virtualvoidFun(intnumber=10){std::coutA::Funwithnumbernumberendl;}};classB:publicA{public:virtualvoidFun(intnumber=20){std::cout”B::Funwithnumber’’numberendl;}};intmain(){Bb;A&a=b;a.Fun();return0;}解答:B::Funwithnumber10。虚函数动态绑定到B,但缺省实参是编译时候确定的10,而非20。构造函数和析构函数中的虚函数构造派生类对象时,首先运行基类构造函数初始化对象的基类部分。在执行基类构造函数时,对象的派生类部分是未初始化的。实际上,此时对象还不是一个派生类对象。撤销派生类对象时,首先撤销它的派生类部分,然后按照与构造顺序的逆序撤销它的基类部分。在这两种情况下,运行构造函数或析构函数时,对象都是不完整的。为了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化。在基类构造函数或析构函数中,将派生类对象当作基类型对象对待。.8•如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本。18:以下哪些做法是不正确或者应该极力避免的()。(多选)(2012•搜狗)A.构造函数声明为虚函数B.派生关系中的基类析构函数声明为虚函数C.构造函数调用虚函数D.析构函数调用虚函数解答:ACD。构造函数和析构函数是特殊的成员函数,在其中访问虚函数时,C++采用静态联编,即在构造函数或析构函数内,即使是使用虚函数名”的形式来调用,编译器仍将其解释为静态联编的“本类名::虚函数名”,因而这样会与使用者的意图不符,应该尽量避免。9.2.2虚函数表指针(vptr)及虚基类表指针(bptr)C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括:virtualfunction机制:用以支持一个有效率的“执行期绑定”;virtualbaseclass:用以实现多次出现在继承体系中的基类,有一个单一而被共享的实体。19:一般情况下,下面哪些操作会执行失败?()(多选)(2012•搜狗)classA{public:stringa;voidfl(){printf(HelloWorld);}voidf2(){a=HelloWorld;printf(%s,a.c_str());}virtualvoidf3(){printf(HelloWorld);}virtualvoidf4(){a=HelloWorld;printf(%s,a.c_str());}};A.A*aptr=NULL;aptr-f1();.9•B.A*aptr=NULL;aptr-f2();C.A*aptr=NULL;aptr-f3();D.A*aptr=NULL;aptr-f4();解答:BCD。因为A没有使用任何成员变量,且fl函数是非虚函数(不存在于具体对象中),是静态绑定的,所以A不需要使用对象的信息,故正确。在B中使用了成员变量,而成员变量只能存在于对象中:C中f3是虚函数,需要使用虚表指针(存在于具体对象中);D同C。可见BCD都需要有具体存在的对象,故不正确。20:请问下面代码的输出结果是什么?classA{public:A(){a=l;b=2;}private:inta;intb;};classB{public:B(){c=3;}voidprint(){coutc;}private:intc;};
本文标题:C++经典笔试题(附答案)
链接地址:https://www.777doc.com/doc-2901817 .html