• C++面经


    指针和引用的区别

    指针定义的时候不用初始化,后期也可以修改指向,占内存空间,可以有多级指针

    引用定义的时候必须要初始化,后期不可以改变指向,它只是代表一个别名,不占内存,引用不能有多级引用

     堆和栈的区别

    堆的内存空间必须要是malloc  new来申请,并且必须要用 free  delete来相应的回收内存,栈的话自己会回收

     new和delete是如何实现的,new 与 malloc的异同处

    new底层是用malloc来实现的

    如果是对象的话

    1,用malloc来申请一块内存

    2,然后在这块内存上调用构造函数

    delete底层使用free来实现

    如果是对象

    1,先调用析构函数

    2,干掉这块内存

    C和C++的区别

    C只是高级语言

    C++是面向对象语言,C++多了三大特性,继承,重载,多态

     C++、Java的联系与区别,包括语言特性、垃圾回收、应用场景等(java的垃圾回收机制)

    语言特性的话:c++ 有指针,多继承,强制类型转换

    Java 有垃圾回收机制能够自动释放掉申请的内存,而C++是以能够操作内存著称,但是很容易带来一些错误

    应用场景:c++用于底层和中间件,java用于高层

    Struct和class的区别

    struct 默认使用 public成员权限,默认使用private成员权限

     define 和const的区别(编译阶段、安全性、内存占用等)

    编译阶段:define处于编译阶段直接替换,const处于运行期

    安全性:define 没得类型检查,const有类型检查

    内存占用:define不占用内存,const因为实质上还是一个变量所以要占用内存

     在C++中const和static的用法(定义,用途)

    const可以修饰函数和变量,修饰类成员函数的话就代表函数里面的成员变量都不能修改

    修饰指针变量的时候又分为顶层const和底层const,分别代表内容和指向不能改变

    static三大功能

    1,修饰全局变量的时候,有隐藏作用,该变量只有这个源文件能够使用,可以方便变量名重复使用

    2,初始化为0

    3,局部持久化,可以在函数里面修饰变量的时候,能够保存上次调用的时候的值

    ‘’

     C++中的const类成员函数(用法和意义)

    在类成员函数的后面加上一个const

    void f() const
     {
     }

    这样代表成员函数里面的类成员不能修改,一般用于只读函数中,不想你修改值

    计算下面几个类的大小:
    class A {};: sizeof(A) = 1;        //空的,会有一个字节,避免申请两个对象公用内存
    class A { virtual Fun(){} };: sizeof(A) = 4(32位机器)/8(64位机器);  //里面含有虚函数指针
    class A { static int a; };: sizeof(A) = 1;      //相当于空类,因为静态存储在静态区
    class A { int a; };: sizeof(A) = 4;
    class A { static int a; int b; };: sizeof(A) = 4;

     给一个代码,求输出结果
    class A
    {
    public:
    A(int x){}
    }
    问:A a = 1;是否正确, 如果正确, 那么它调用了哪些函数?

    转换构造函数,能够隐式转换,可以使用 explicit强制不能转

     C++的STL介绍(这个系列也很重要,建议侯捷老师的这方面的书籍与视频),其中包括内存管理allocator,函数,实现机理,多线程实现等

    序列式容器:vector  deque  list

    关联式容器:set  mulset  map  mulmap

    容器配接器:queue  stack    priority_queue

    内存分配器:allocator

    C++中的重载和重写的区别:

    重载:是在同一个类中,两个相同名字的函数,需要函数参数列表不相同

    重写:virtual 关键字修饰的函数,子类可以再去写一遍,如果写了就使用新的这个,并且严格意义上来说这个还是属于父类,返回值,参数列表都要一样,不写就是用父类的这个

     介绍面向对象的三大特性,并且举例说明每一个

    重载:就是同类的时候可以重载运算符,重载函数

    继承:呃,不介绍了

    多态:c++使用虚函数来实现多态,可以实现上行转换和下行转换

     多态的实现

    在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数

      1:用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。  

      2:存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。  

    C++虚函数相关(虚函数表,虚函数指针),虚函数的实现原理(热门,重要)

     推荐博文:https://blog.csdn.net/lyztyycode/article/details/81326699   这篇写的贼好

    虚函数实现原理,其实就是两个组成,虚函数表和虚函数表指针

    虚函数表是在类里面的,虚函数表指针属于创建的对象,如果对象想要使用虚函数的话,那么就要用指针找到相对应的虚函数,最开始虚函数指针都是指在虚函数表的第一个位置

    然后虚函数在子类实现的时候有个名词叫做重写,意思也就是在原来位置重现了这个函数

    单继承:

      没有重写:虚函数表就是按照定义的顺序来做的虚函数表,子类继承就把子类的接在了父类后面

      有重写:子类重写了父类的虚函数,那么就把父类原先那个位置的虚函数改成新的那个,这个也是为什么多态能够实现的原因,因为始终指向没有变,但是我改变了父类的虚函数表的内容

    多继承:

      没有重写:会拥有多个虚函数表,自己的虚函数接在了第一个虚函数表里面

      有重写:会把所以父类虚函数表和重写同名的都改掉

     实现编译器处理虚函数表应该如何处理

    推荐博文:https://wenku.baidu.com/view/cd87c405f12d2af90242e680.html  基本能理解原理

    编译器如果检测virtual关键字,那么就会创建一个虚函数表,然后如果创建对象的话就会在前面加一个字段存储虚函数表指针

    如果调用虚函数,编译器会做一个简单的替换,替换成用指针求调用虚函数

     析构函数一般写成虚函数的原因

    如果基类指针向派生类对象,则删除此指针时,我们希望调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
    若使用基类指针操作派生类,需要防止在析构时,只析构基类,而不析构派生类

    构造函数为什么一般不定义为虚函数

    因为调用虚函数需要虚函数指针,虚函数指针又是对象专有,但是构造函数使用虚函数的话,都没得对象就不能搞了

     构造函数或者析构函数中调用虚函数会怎样

    https://www.cnblogs.com/vincently/p/4754206.html

    引用里面的解释的话就是:结果会变成并没有实现多态,调用的依旧会是父类的虚函数

    构造:因为基类的构造在子类构造之前,所以相当于子类的虚函数指针成员什么的都还没有建造出来,所以到基类还是基类的虚函数

    析构:因为到了析构里面就默认所有成员都不存在了,就和上面一个道理了

     纯虚函数

    纯虚函数的格式   virtual  f()=0;

    代表我不实现,留给子类去实现,带有纯虚函数的类也叫抽象类,不能够实例对象出来,子类必须实现,主要解决的是多态问题,面向对象的思想

    动物基类 不能实现,老虎,狮子等派生类可以给出对象,所以嘛出现了纯虚函数抽象类这个东西

    静态绑定和动态绑定的介绍

    动态绑定时虚函数独有的,其他都是静态绑定

    摘大佬的一段话‘

    (1)对象的静态类型 :对象在声明时采用的类型,是在编译期确定的。
    (2)对象的动态类型:目前所指对象的类型,是在运行期决定的,对象的动态类型可以更改,但对象的静态类型无法更改。
    (3)静态绑定:绑定的是对象的静态类型,其特性(如函数)依赖于对象的静态类型,发生在编译期。
    (4)动态绑定:绑定的是对象的动态类型,其特性(如函数)依赖于对象的动态类型,发生在运行期。


    动态绑定也就是能在运行的时候一直变化,你不能知道它哪一时刻属于什么类型,调用的哪个函数,而你一个普通函数,一眼就知道你干啥了

    引用是否能实现动态绑定,为什么引用可以实现

    引用和指针都是在运行期确定的,普通的是编译器

    引用和指针都不改变类型,只是要一个地址和内存大小,而普通的牵扯到类型转换就不太顶

     深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)

    浅拷贝也就是把值自己拥有的值直接传给对面,但是如果成员里面有指针的时候非常不安全,因为指针的值是一个地址,相当于两个对象的指针指向同一块内存,析构的时候对同一块内存析构两下,然后造成内存泄漏,哦凉凉

    深拷贝直接把它的内存都复制一份,然后指针再指向新的这块区域,对象默认拷贝和赋值都是浅拷贝

     介绍C++所有的构造函数

    1,普通构造函数,就是普通那样创建

    2,拷贝构造函数:利用现有对象给其他对象创建     函数传参     函数返回值 都会调用拷贝构造

    3,转换构造函数:就是只有一个参数,可以有默认参数,它会你赋值一个值的时候直接转换成一个对象

    结构体内存对齐方式和为什么要进行内存对齐?

     结构体对齐方式看你当前最大变量的内存占用字节数,然后必须是当前的倍数

    因为底层读取内存块的时候,处理器只能一次读取这么大的内存块,如果变量横跨两个内存块,那么还要读取两个内存块,然后分别取出来,贼麻烦

     内存泄露的定义,如何检测与避免?

    内存泄漏也就是使用堆内存忘记释放掉,然后到程序外面又没有指针能够指向它,内存就这样一直被占用着,无法再次使用

    避免神器:智能指针

    手写实现智能指针类

    https://blog.csdn.net/lizhentao0707/article/details/81156384

    智能指针是为了解决掉指针所产生的内存泄漏的问题,用来代替指针的,会自动释放掉内存

    有 shared_ptr    auto_ptr    weak_ptr     unique_ptr

    需要知道的是,它所实现的自动回收内存机制,是你如果要多个指针指向同一块内存区域,只能利用之前所创建的智能指针创建,利用的是拷贝构造函数和重载赋值运算来实现的

    所以当两个只能指针都是拿一块内存来初始化的时候,并不会有引用计数增加的出现,这点要特别注意

    手写指针还是不太熟练,明天写一个完整的出来

  • 相关阅读:
    20190430-screen、client、offset、scroll等JS中各种宽度距离
    20190423-Vscode与Sass不得不说的秘密(>^ω^<)
    20190422-外部导入CSS样式之link、CSS@import、Sass分音
    20190421-那些年使用过的CSS预处理器(CSS Preprocessor)之Sass and Less
    20190421-那些年使用过的CSS预处理器(CSS Preprocessor)
    20190409-层叠の层叠上下文、层叠水平、层叠顺序、z-index、伪元素层叠
    20190408-规范书写
    20190404-transition、transform转换、animation、媒体查询
    20190402-display展现、float浮动
    20190401-颜色书写
  • 原文地址:https://www.cnblogs.com/Lis-/p/12313778.html
Copyright © 2020-2023  润新知