C++面试题目集合(持续跟新)

来源:互联网 发布:域名怎么防腾讯拦截 编辑:程序博客网 时间:2024/05/29 14:34

与我前面写的C语言进阶知识点遥相呼应。

这才是C++面试,网上的面试题有些太简单了。

C++面试题目最多集中在对象的内存模型,记住了:如果用c/c++,内存都不清楚,还写个屁的程序!

1.C++的虚函数是怎样实现的?

      C++的虚函数使用了一个虚函数表来存放了每一个虚函数的入口地址,这个虚函数表又使用一个虚函数指针来进行访问。通常,虚函数指针都放在对象模型的第一个位置存放,这样访问徐函数指针的速度最快,没有偏移量。通过虚函数指针,找到虚函数表,进而再做一个次偏移量计算,来得到真实虚函数的入口地址,从而访问了虚函数。这样看来,访问一个虚函数将使用两次间接计算,故要失去一些时间效率。另外,使用了虚函数,那么就要消耗一些空间,存放虚函数指针。但是,这都是值得的,为了实现多态。

2. 虚函数表是每个对象一个还是每个类一个呢?

     这个事搜狗的面试题目。其实讨论过,我之前看到这个问题,立马就想到了this指针。http://topic.csdn.net/u/20081031/16/6784c211-a475-4af5-a331-c3df887a2d0c.html比较详细的讨论。

    每个类只有若干个虚拟函数表,每个对象可以有若干个虚函数表指针。(这都是在多重继承的情况下出现的。单重继承的情况下,就是一个对象有一个虚函数表指针,每一个类有一个虚函数表)函数调用的时候会将this指针作为参数发过去,所以没有必要为每一个对象做一个虚拟函数表。
     “每个类有一个或多个虚函数表,单纯的继承下来的类有一个虚函数表,虚继承下来的类就有可能有多个虚函数表(只是有可能),对象没有虚函数表,但是有指向虚函数表的指针。对象之所一能调用“自己的函数”,是因为类的成员函数不知不觉的在编译时多了一个this指针参数来识别成员数据属于哪个对象。”

    关于这个问题,在《more effective c++》中的条款24有详细叙述,的确是每一个类的一个虚函数表。至于放的的位置,书中也有讲述。

3.函数指针和指针函数的区别?

     就想通过这个问题来判断我的C水平?C语言我看的数都有三本。

    函数指针,一个指针,指向了函数的调用地址。  void (*fun)(void)

  指针函数,就是一个函数的返回值是指针。 int *  fun(void)

  这道题目我真的很冤,指针函数,我真的没有听说过。

   数组指针和指针数组我知道什么区别

4. C++ 深拷贝和浅拷贝的区别?如果要delete一个浅拷贝,需要注意什么条件?

   现在有一个指针p1指向了一个内存空间m1;

   浅拷贝就是再用一个新的指针p2指向这片内存空间m1;

   深拷贝就是用一个新的指针p3指向m1的副本m2

   delete一个浅拷贝,首先要测试是不是有其它的指针还在指向这片空间。不然,直接就是野指针了。为什么野指针那么是绝对要禁止的?野指针现在指向了一片内存区间,这片内存区间以前是有意义的,现在被释放了,操作系统可能会讲这边区间放上其它程序数据。那么,野指针仍然指向了这片区间。如果此时使用野指针,改变了这片内存的数据,那么程序应该直接崩溃。而且,这样子的崩溃可能出现,可能等一会儿出现,不定。带来的bug很难查找。

5.  dynamic_cast的用法?

http://blog.csdn.net/wingfiring/article/details/633033

作为四个内部类型转换操作符之一的dynamic_cast和传统的C风格的强制类型转换有着巨大的差别。除了dynamic_cast以外的转换,其行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转换的对象。而dynamic_cast则不然。在这里,不再讨论其他三种转换和C风格的转换。
首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。
先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.
也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的。

struct B1{    virtual ~B1(){}};struct B2{    virtual ~B2(){}};struct D1 : B1, B2{};int main(){    D1 d;    B1* pb1 = &d;    B2* pb2 = dynamic_cast<B2*>(pb1);//L1    B2* pb22 = static_cast<B2*>(pb1);  //L2    return 0;}

pb2将会为NULL指针,pb22将会编译出错。

http://baike.baidu.com/view/1745213.htm

dynamic_cast < type-id > ( expression )  

该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void*;  

如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。  dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。  

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;  

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

http://blog.csdn.net/wingfiring/article/details/633033

dynamic_cast 确实很好地解决了我们的问题,但也需要我们付出代价,那就是与 typeid 相比,dynamic_cast 不是一个常量时间的操作。为了确定是否能完成强制类型转换,dynamic_cast`必须在运行时进行一些转换细节操作。因此在使用 dynamic_cast 操作时,应该权衡对性能的影响


5. 请阅读以下的代码,试试看,你能发现错误或者不恰当地方吗?(提示:   不止一处)
http://topic.csdn.net/t/20061129/14/5194019.html

class   Wheel{};class   Color{};class   Car{private:    Wheel*   wheels;public:    Car(int   wheel_count){wheels   =   new   Wheel[wheel_count];}    ~Car(){delete   wheels;}};class   Roadster   :   public   Car{public:    Color   color;    Roadster(){};    Roadster(const   Roadster&   rs)    {        this-> color   =   rs.color;    }    ~Roadster(){};    Roadster&   operator=(const   Roadster&   rhs)    {        this-> color   =   rhs.color;    }    const   Roadster&   clone()    {        Roadster   the_new   =   *this;        return   the_new;    }};int   main(int   argc,   char*   argv[]){    Roadster*   yours   =   new   Roadster;    Roadster   mine;     mine   =   yours-> clone();    Car*   pCar   =   yours;    delete   pCar;    return   0;}; 

修改如下:

class   Wheel{};class   Color{};class   Car{private:    Wheel*   wheels;    //1.   没有保存wheels的下标    //2.   最好用vectorpublic:    Car(int   wheel_count){wheels   =   new   Wheel[wheel_count];}        ~Car(){delete   wheels;}    //3.   析构函数要虚拟    //4.   delete   wheels;   ->   delete   []wheels;    //5.   要提供拷贝构造函数    //6.   要重载赋值操作符};class   Roadster   :   public   Car{public:    Color   color;    //7.   成员变量要私有    Roadster(){};    //8.   要调用父类的构造函数    Roadster(const   Roadster&   rs)    {        this-> color   =   rs.color;    }    //9.   要调用父类的拷贝构造函数    ~Roadster(){};    //10.   析构函数要虚拟(原则:析构函数要么虚拟且公有,要么保护且非虚拟)    Roadster&   operator=(const   Roadster&   rhs)    {        this-> color   =   rhs.color;    }    //11.   需要调用父类的赋值操作符    //12.   没有返回值    //13.   返回的类型最好是const   Roadster&,   而不是Roadster&    const   Roadster&   clone()    {        Roadster   the_new   =   *this;        return   the_new;    }    //14.   不能返回局部变量的引用    //15.   按照这里的逻辑,   其实可以直接返回*this};int   main(int   argc,   char*   argv[]){    //16.   这里的{}风格与前面的不一致    Roadster*   yours   =   new   Roadster;    Roadster   mine;     mine   =   yours-> clone();    //17.   最好是一行只有一条语句,   不要两条语句放在一行    //18.   其实这里可以直接是Roadster   mine   =   yours-> clone();    Car*   pCar   =   yours;    delete   pCar;    //我认为这里是没有问题的,作为Car类的使用者,他在这里用是没有问题的,错误的只是Car类的代码    return   0;}; 

6.C++程序进入main函数之前,退出main函数之后会做些什么?

main函数执行之前,主要就是初始化系统相关资源:
1.设置栈指针
2.初始化static静态和global全局变量,即data段的内容
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容
4.运行全局构造器,C++中构造函数
5.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数

main 函数之后会执行相反的工作。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 刚生的小羊羔不吃奶怎么办 刚出生的婴儿不会吸奶怎么办 生完小孩七十天妈妈咳嗽怎么办 带欣的名字三个字儿的怎么办 二十多岁的儿子沉迷游戏网络怎么办 为什么打开游戏网络却用不了怎么办 打来微信网页版显示证书错误怎么办 开了家定制家具店生意不好怎么办 宝宝起风疹怎么办要注意的问题 超市买的内裤西铁牌子没去掉怎么办 没申请生产许可证贴标了怎么办 淘宝没有品牌非要我写品牌怎么办没 意外怀孕明明一直用安全套的怎么办 找不到百度网盘的dns地址怎么办 小米众筹到了发货时间不发货怎么办 不知道电脑宽带连接账号密码怎么办 电脑如果宽带账号密码忘记了怎么办 xp电脑用户名和密码忘了怎么办 电脑的用户名和密码忘记了怎么办 电脑重置后需要用户名和密码怎么办 电脑登录用户名和密码忘记了怎么办 电脑登录用户名和密码忘了怎么办啊 微信无意中点了允许登录怎么办 qq号码登录微信无法验证怎么办 注册微信公众号邮箱激活不了怎么办 不是自己申请的qq号忘密码怎么办 联通宽带拨号账号密码忘记了怎么办 忘了路由器的用户名和密码怎么办 宽带连接用户名和密码忘了怎么办 江西银行网银用户名忘记了怎么办 江西银行网银密码忘了怎么办 广发信用卡网银密码忘了怎么办 刚注册的淘宝账号买不了东西怎么办 隐藏后的wif不知道用户名怎么办 脊柱侧弯术后钢钉断了一根怎么办 对法院执行裁定申请复议过期怎么办 自己家店名被别人注册了商标怎么办 有人去工商局投诉我公司了怎么办 急用钱怎么办啊有没有什么贷款啊 初级会计报名信息表没打印怎么办 电工证复审流程时间过了怎么办