• C/C++面试题


    1.new、delete、malloc、free之间的关系
    malloc和free都是C/C++标准库函数。new/delete是运算符。
    都是用于动态申请和释放内存。
    new会调用对象的构造函数,delete调用对象的析构函数,而malloc和free只能申请和释放内存。
    由于 malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加给 malloc/free。

    2.delete和delete []的区别
    delete 只会调用一次析构函数,而 delete[] 会调用每一个成员函数的析构函数。
    delete[]删除一个数组,delete删除一个指针。简单来说,用new分配的内存用delete删除;用new[]分配的内存用delete[]删除。

    3.C++有哪些性质(面向对象特点)
    封装、继承和多态

    4.子类析构时要调用父类的析构函数吗?
    析构函数调用的次序是先子类的析构后父类的析构;定义一对象时先调用父类的构造函数然后在调用子类的构造函数

    5.介绍多态、虚函数和纯虚函数。
    多态:对于不同对象接受相同信息时产生的不同动作;例如,对于三角形和矩形而言,计算各自的面积的公式不一样,都是调用相同的方法(动态多态)。
    多态分为两类:静态多态(静态多态的函数地址早绑定 - 编译阶段确定函数地址):函数重载和运算符重载属于静态多态,复用函数名;动态多态(动态多态的函数地址晚绑定 - 运行阶段确定函数地址):派生类和虚函数实现运行时多态

    #include <iostream> 
    using namespace std;
     
    class Shape {
       protected:
          int width, height;
       public:
          Shape( int a=0, int b=0)
          {
             width = a;
             height = b;
          }
          virtual int area()
          {
             cout << "Parent class area :" <<endl;
             return 0;
          }
    };
    class Rectangle: public Shape{
       public:
          Rectangle( int a=0, int b=0):Shape(a, b) { }
          int area ()
          { 
             cout << "Rectangle class area :" <<endl;
             return (width * height); 
          }
    };
    class Triangle: public Shape{
       public:
          Triangle( int a=0, int b=0):Shape(a, b) { }
          int area ()
          { 
             cout << "Triangle class area :" <<endl;
             return (width * height / 2); 
          }
    };
    // 程序的主函数
    int main( )
    {
       Shape *shape;
       Rectangle rec(10,7);
       Triangle  tri(10,5);
     
       // 存储矩形的地址
       shape = &rec;
       // 调用矩形的求面积函数 area
       shape->area();
     
       // 存储三角形的地址
       shape = &tri;
       // 调用三角形的求面积函数 area
       shape->area();
       
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    虚函数:在基类中冠以关键字virtual的成员函数、它提供了一种接口界面,允许在派生类中对基类的虚函数重新定义
    纯虚函数:在基类中为其派生类保留一个函数的名字,以便派生类在需要时对它进行定义。作为借口而存在的纯虚函数不具备函数的功能,一般不能直接调用(没实现)。从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类称为抽象类,抽象类是必须作为派生其他类的基类,而不能直接创造对象实例。

    6.求下面函数的返回值(微软)

    int func(x)
    {
        int countx = 0;
        while(x)
        {
            countx ++;
            x = x&(x-1);
        }
        return countx;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    & 按位与如果两个相应的二进制位都为1,则该位的结果值为1,否则为0,也是二进制与全1为1,好那我们先把9999转化为二进制数:10011100001111
    如x最后一位是1,则x-1最后一位变为0,前面不变,而1 & 0 = 0,所以最后一位的1变为了0
    也就是10011100001111 & 10011100001110 = 10011100001110
    此时最后一位为0 再减1 10011100001101 也就是10011100001110 & 10011100001101 = 10011100001100
    每次相应于影响了最后一个带1的数前面保持不变 直到 x 为0 为止
    该函数计算参数x的二进制中1的个数 8 次

    7.什么是“引用”?声明和使用“引用”要注意哪些问题?
    引用变量是一个别名,他是某个已存在变量的另一个名字。引用声明完毕后,相当于目标变量有两个名称,即该目标原名称是引用名,并且不能再将该引用名作为其他变量的别名。

    8.将“引用”作为函数参数有哪些特点?
    (1)引用是对目标变量的别名,被调函数函数的形参被当做主调函数实参的一个别名来使用,所以在被调函数对形参的操作实际上是对目标对象的操作。
    (2)使用引用传递参数,在内存中没有产生实参的副本,他是直接对实参操作;而使用一般变量传递参数时需要给形参分配存储单元,此时的形参变量时实参的一个副本。
    (3)引用容易使用,更清晰, 引用相对于指针来说具有更好的可读性和实用性

    9.在什么时候需要使用“常引用”?
    既要提高程序的效率,又要保护传递给函数的数据不在函数中被改变。

    10.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
    好处:在内存中不产生被返回值的副本;
    ①不能返回局部变量的引用,主要原因是局部变量会在函数返回后被销毁,因此返回的引用就成为了“无所指”的引用,程序进入未知状态。
    ②不能返回函数内部new分配的内存的引用,虽然不存在局部变量被销毁问题,但是因为被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际变量,那么这个这个引用所指向的空间就无法释放,造成内存泄漏。

    11.结构与联合有何区别?
    ①结构体和联合体都是由多个不同的数据类型成员组成,但在任何一时刻,联合体中只存放了一个被选中的成员(所有成员公用一块地址空间),而结构体的所有成员都存在(不同成员的存放地址不同)。
    ②对于联合体的不同成员赋值,将会对其他成员重写。原来的成员的值就不存在了,而对于结构体不同成员赋值是互不影响的。

    12.重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
    重载:允许存在多个同名函数,而这些函数的参数不同(或许参数个数不同,或许参数类型不同,或许两者都不同);
    重写:子类重新定义父类虚函数。

    13.分别写出bool,int,float,指针类型的变量a 与“零”的比较语句

    if(!a){}//bool
    if(0==a){}//int
    if(NULL==a){}//指针类型
    //float
    const float EPSINON = 0.000001;
    if(a<EPSINON && a>(-EPSINON )){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    14.请说出const与#define相比,有何优点?
    const作用:定义常量、修饰函数函数、修饰函数返回值三个作用。被const修饰后受到强制保护,可以预防意外的变动,能提高程序的健壮性。
    1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
    2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

  • 相关阅读:
    【js】event.target event.cuurenttarget 元素绑定
    RT-DETR优化改进:IoU系列篇 | Inner-IoU融合MPDIoU,创新十足,2023年11月最新IoU改进
    数据结构与算法 -- 链表
    java计算机毕业设计家政服务网站源程序+mysql+系统+lw文档+远程调试
    一文带你彻底弄懂ZGC
    GVA快速使用
    产业互联网,并非消费互联网式的置身事外
    STM32H743 RTC精密数字校准 深度剖析
    MySQL数据库如何线上修改表结构
    避免被反洗钱冻住的方法
  • 原文地址:https://blog.csdn.net/qq_41877840/article/details/125271562