zoukankan      html  css  js  c++  java
  • C++常见面试问题

    1.struct和union

    --union中只存放了一个被选中的成员;而struct的所有成员都存在

    --struct变量的总长度等于所有成员长度之和;Union变量的长度等于最长的成员的长度。

    2.static和const

    --static:

    修饰变量:

    a.static修饰局部变量,它就改变了局部变量的存储位置(从原来的栈中存放改为静态存储区)及其生命周期(局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能进行访问),但未改变其作用域。 

    b.static修饰全局变量,并为改变其存储位置及生命周期,而是改变了其作用域,使当前文件外的源文件无法访问该变量,好处如下:(1)不会被其他文件所访问,修改(2)其他文件中可以使用相同名字的变量,不会发生冲突。对全局函数也是有隐藏作用。

    修饰类成员:

    a.static修饰类的成员变量:实际使其成为类的全局变量,会被类的所有对象共享,包括派生类的对象。因此,static成员必须在类外进行初始化(初始化格式: int base::var=10;),而不能在构造函数内进行初始化。

    b.static修饰类的成员函数:(1)使这个类只存在这一份函数,所有对象共享该函数,不含this指针;(2)静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。当static成员函数在类外定义时不需要加static修饰符。

    --const

    a.修饰变量变量不可以被修改;

    b.修饰指针:char * const p【常指针】  ;;;const char *p【指向常量的指针变量】

    3.指针与引用

    --指针是变量,引用是别名

    --指针可以为null,引用不可以为空且必须初始化

    --指针可以改变,引用只能一直引用一个

    4.重载(overload)、重写(override)、覆盖(overwrite)

    --overload

    --override: 继承体系中,子类实现父类虚函数

    --overwrite:也是在继承体系中,子类覆盖了父类的方法

    5.深拷贝与浅拷贝

    --浅拷贝:默认的复制构造函数只是完成了对象之间的位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

    --深拷贝:自定义复制构造函数需要注意,对象之间发生复制,资源重新分配,即A有5个空间,B也应该有5个空间,而不是指向A的5个空间。

    6.虚继承和虚基类

    --在多重继承(菱形继承)下,虚继承保证了最终的派生类只有基类的一份拷贝。而在根部的基类称为虚基类

    class istream : public virtual ios { ... };
    class ostream : virtual public ios { ... };
    // iostream inherits only one copy of its ios base class
    class iostream: public istream, public ostream { ... };

    7.排序算法

    8.容器及特点

    9.TCP为什么要三次握手而不是两次:防止失效的请求又到达服务器,产生错误。

    三次握手的最主要目的是保证连接是双工的,可靠更多的是通过重传机制来保证的

    --TCP可靠传输实现:

    TCP 连接的每一端都必须设有两个窗口——发送窗口和接收窗口。TCP 的可靠传输机制用字节的序号进行控制。TCP 所有的确认都是基于序号而不是基于报文段。
    发送过的数据未收到确认之前必须保留,以便超时重传时使用。发送窗口没收到确认不动,和收到新的确认后前移。

    发送缓存用来暂时存放: 发送应用程序传送给发送方 TCP 准备发送的数据;TCP 已发送出但尚未收到确认的数据。

    接收缓存用来暂时存放:按序到达的、但尚未被接收应用程序读取的数据; 不按序到达的数据。

     --TCP报文格式

    (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
      (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
      (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
        (A)URG:紧急指针(urgent pointer)有效。
        (B)ACK:确认序号有效。
        (C)PSH:接收方应该尽快将这个报文交给应用层。
        (D)RST:重置连接。
        (E)SYN:发起一个新连接。
        (F)FIN:释放一个连接。

     需要注意的是:
      (A)不要将确认序号Ack与标志位中的ACK搞混了。
      (B)确认方Ack=发起方Req+1,两端配对。

    10.线程和进程,线程可以共享进程里的哪些东西。 知道协程是什么吗

    --线程共享进程的地址空间,全局变量(数据和堆)。在一个进程中,各个线程共享堆区,而进程中的线程各自维持自己的栈。

    --协程:

    定义:协程其实可以认为是比线程更小的执行单元。为啥说他是一个执行单元,因为他自带CPU上下文。

    11. makefile

    --makefile关系到了整个工程的编译规则makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

    --makefile成为了一种在工程方面的编译方法,其本质都是在“文件依赖性”上做文章

    --源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File.

    12. 大端小端模式

    --大端:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

    --小端:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

    http://www.cnblogs.com/LUO77/p/5771237.html

    ===================================================================

    13. new/delete与malloc/free的区别

    new/delete malloc/free
    c++操作符 c库函数
    new调用构造函数,delete调用析构函数 只对内置类型有效
    new返回指定类型的指针,并自动计算大小
    string *ps=new string(10,’9’)
    malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针
     在创建对象的时候就可以初始化
    malloc 只管分配内存,并不能对所得的内存进行初始化
    new分配失败时,返回什么?
    1993年前,c++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new(以及operator new[])以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象: 
    class   widget   {   ...   }; 
    widget   *pw1   =   new   widget;//   分配失败抛出std::bad_alloc   
    if   (pw1   ==   0)   ... //   这个检查一定失败 
    widget   *pw2   =   new   (nothrow)   widget;   //   若分配失败返回0
    if   (pw2   ==   0)   ... //   这个检查可能会成功

    14.多态,虚函数,纯虚函数

    多态:

    --编译时多态:函数重载

    --运行时多态:继承和虚函数

    虚函数:提供一个接口和一份默认的实现

    纯虚函数:提供一份接口(抽象类)

    15.引用

    -作为参数:

    ----直接对传入的对象进行修改;(传指针的时候需要在使用前对指针进行检查)

    ----为了降低复制自定义对象的开销,通常加上const;

    -作为返回值(在内存中不产生被返回值的副本):

    ----返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

    ----

    16.栈内存与文常量区

          char str1[] = "abc";
      char str2[] = "abc";

      const char str3[] = "abc";
      const char str4[] = "abc";

      const char *str5 = "abc";
      const char *str6 = "abc";

      char *str7 = "abc";
      char *str8 = "abc";

      cout << ( str1 == str2 ) << endl;//0  分别指向各自的栈内存
      cout << ( str3 == str4 ) << endl;//0  分别指向各自的栈内存
      cout << ( str5 == str6 ) << endl;//1指向文字常量区地址相同

      cout << ( str7 == str8 ) << endl;//1指向文字常量区地址相同

      结果是:0 0 1 1

      解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;而str5,str6,str7,str8是指针,它们指向相同的常量区域。

    17.复杂声明

    http://blog.csdn.net/zjc156m/article/details/16819357

    =====================================================================

    18.C++对象模型

    non-static数据成员被放置到对象内部,static数据成员、static和nonstatic函数成员放到对象之外。

    19.智能指针

       C++新标准库中定义了两种智能指针shared_ptr和unique_ptr,定义在memory头文件中。

    shared_ptr:允许多个指针指向同一个对象;()

    shared

    --weak_ptr:是一种弱引用,指向shared_ptr所管理的对象 

    --思想:引用计数为0就自动销毁所管理的对象,释放占用的内存

    ----拷贝一次,引用计数加1:

    用shared_ptr初始化另一个shared_ptr

    将其作为参数传递给另一个函数

    作为函数返回值

    ----计数减1的情况:

    给shared_ptr赋值一个新值

    被销毁(离开局部作用域)

    --操作:

    p.get(),p.swap(q)(是共有的操作)、p.unique()、p.use_count()

    --构造:

    ----auto p = make_shared_ptr<vector<string>>();

    ----shared_ptr<int> p(new int(1024));使用直接初始化形式,因为智能指针的构造函数是explicit的

    unique_ptr:独占所指向的对象,不支持拷贝与赋值操作,但是可以通过release()和reset()操作将指针的控制权从一个unique转到另一个unique指针 

     20.虚函数

    --静态函数不可以是虚函数:因为静态成员函数没有this,也就没有存放vptr的地方,同时其函数的指针存放也不同于一般的成员函数,其无法成为一个对象的虚函数的指针以实现由此带来的动态机制。静态是编译时期就必须确定的,虚函数是运行时期确定的。

    --内联函数不可以是虚函数:inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够确定如何去调用的,因而inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。
    因此,内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的。

    --设置虚函数须注意: 
    1:只有类的成员函数才能说明为虚函数; 
    2:静态成员函数不能是虚函数; 
    3:内联函数不能为虚函数; 
    4:构造函数不能是虚函数; 
    5:析构函数可以是虚函数,而且通常声明为虚函数。

    21.一个函数一旦声明为虚函数,那么不管你是否加上virtual 修饰符,它在所有派生类中都成为虚函数    

    构造函数是不能被继承的,但是可以被调用,如果父类重新定义了构造函数,也就是没有了默认的构造函数,子类创建自己的构造函数的时候必须显式的调用父类的构造函数。而其余的三个在我们平常的使用中都可以被继承使用。                                                   22.静态局部变量只对定义它的函数体始终可见,函数体执行完过后虽然还存在,但是无法被其他的使用了                                  23.

    -- public成员可以被类中的函数、友元函数、类的对象、派生类访问。

    --私有继承时,基类的public和protected成员都变成派生类的private类型,因此不可被类外访问。
    --保护继承时,基类的public和protected成员都变成派生类的protected类型,可以被派生类访问。
    --protected成员可以被类中的函数、友元函数、派生类访问,不能被类的对象访问,因此不能在类外被访问
    24.
    基类对象与派生类对象之间存在赋值相容性,包括以下几种情况:
    – 把派生类对象赋值给基类对象。
    – 把派生类对象的地址赋值给基类指针。
    – 用派生类对象初始化基类对象的引用。

     25.const

    char* const p = &a;//常指针,指向不可以改变,数量可以改变

    char const *p = &b;//指向常量的指针,b是常量

    const修饰参数、返回值、成员函数 ,non-const 版本可以调用const版本,反之则不行。                                                       26.

    volatile (容易改变的)作用是避免编译器优化,说明它是随时会变的,它不是 non-const,和const不矛盾。被const修饰的变量只是在当前作用范围无法修改,但是可能被其它程序修改。优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

    27.

    引用、const成员变量、基类构造函数一定要通过初始化列表来实现。 static类型不是类对象成员,不需要通过初始化列表来初始化                                                                                                                                                                                                                                                                                                                                                                             

  • 相关阅读:
    「Baltic2015」Network
    noip模拟赛 蒜头君的排序
    noip模拟赛 蒜头君的兔子
    codevs2171 棋盘覆盖
    noip模拟赛 蒜头君的坐骑
    noip模拟赛 蒜头君的树
    noip模拟赛 蒜头君打地鼠
    noip模拟赛 密码
    noip模拟赛 轰炸
    noip模拟赛 毁灭
  • 原文地址:https://www.cnblogs.com/lp3318/p/6545676.html
Copyright © 2011-2022 走看看