C++ 面试基础之一


C/C++的区别和联系

联系

C++是C的超集,兼容C的大部分的语法。

区别

  • C是面向过程的语言,C++是面向对象的语言
  • C不支持函数的重载,C++支持
  • C不支持引用,C++支持引用
  • C++全部变量的默认链接属性是外链接,而C是内连接。
  • C和C++的动态管理内存的方法不一样,C是使用malloc/free函数,而C++除此之外还有new/delete关键字。
  • C++的类是C所没有的。但是C中的struct是可以在C++中正常使用的,并且C++对struct进行了进一步的扩展,使struct在C++中可以和class一样当做类使用,而唯一和class不同的地方在于struct的成员默认访问修饰符是public,而class默认的是private。

C/C++程序占用的内存空间

  • 堆区:由程序员申请或者释放内存。操作方式是先进先出。
  • 栈区:由编译器自动分配和释放内存。栈存储着函数的参数以及局部的变量。操作方式是先进后出。
  • 全局区:全局变量和静态变量存储在这里。初始化的全局变量和静态变量在一块区域(DATA段), 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(BSS段)。- 程序结束后由系统释放。
  • 常量存储区:存储程序中的常量,不允许修改,程序结束后由系统释放。程序结束后由系统释放。
  • 代码区:存放程序的可执行的二进制的代码。
    |----------------------| 高地址
    | 栈区(Statk) | -->向下增长
    |----------------------|
    | 堆区(Heap) | -->向上增长
    |----------------------|
    | 未初始化(BSS) |
    |----------------------|
    | 初始化(Data) |
    |----------------------|
    | 常量存储区 |
    |----------------------|
    | 正文段(Text) |
    |----------------------| 低地址

C++程序编译链接的过程

  1. 预处理是 C 语言程序从源代码变成可执行程序的第一步,主要是 C 语言编译器对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、条件编译的选择等。
  2. 编译:编译之前,C 语言编译器会进行词法分析、语法分析 (-fsyntax-only) ,接着会把源代码翻译成中间语言,即汇编语言 。 编译程序工作时,先分析,后综合,从而得到目标程序。所谓分析,是指词法分析和语法分析;所谓综合是指代码优化,存储分配和代码生成。
  3. 汇编:将编译完的汇编代码文件翻译成机器指令,并生成可重定位目标程序的.o文件,该文件为二进制文件,字节编码是机器指令。
  4. 链接:通过链接器将一个个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。
    由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
    链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
    编译过程

    https://www.cnblogs.com/kekec/p/3238741.html
    https://www.cnblogs.com/Lynn-Zhang/p/5377024.html

struct和class的区别

  • struct是C中定义结构体用的关键字,C++对其进行了扩展,使其可以像C++中class一样使用。
  • struct定义的结构体默认的访问的权限是public,而class定义的类的默认访问权限是private。

const关键字

  • 修饰变量,表示变量不可改变
  • 修饰指针,可表示常量指针或者指针常量
  • 常量引用,常用于修饰函数的形参的引用类型。避免了参数的拷贝,而且避免方法对于参数值的修改。
  • 修饰成员函数,说明该成员函数内不能修改成员变量。

volatile

  • volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
  • 使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据。

static

  • 修饰普通变量,变量存储在C++内存中的全局区。在 main 函数运行前就分配了空间。
  • 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。
  • 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。
  • 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。

什么时候开始分配并初始化的
全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。

https://www.cnblogs.com/33debug/p/7223869.html
https://www.cnblogs.com/kkdd-2013/archive/2013/12/05/3459888.html (比较详细)
https://segmentfault.com/q/1010000004157283/a-1020000004158311 (什么时候初始化)

指针和引用的区别

  • 指针是一个实体,而引用仅是个别名;
  • 引用必须被初始化,指针不必;
  • 引用只能在定义时被初始化一次,之后不可变;指针可以改变所指的对象;
  • 可以有const指针,但是没有const引用;
  • 不存在指向空值的引用,但是存在指向空值的指针,即引用不能为空,指针可以为空;
  • “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
  • 指针和引用的自增(++)运算意义不一样;
  • 程序为指针变量分配内存区域,而引用不需要分配内存区域;
    https://blog.csdn.net/wanwenweifly4/article/details/6739687

inline 内联函数

特征

  • 相当于把内联函数里面的内容写在调用内联函数处;
  • 相当于不用执行进入函数的步骤,直接执行函数体;
  • 相当于宏,却比宏多了类型检查,真正具有函数特性;
  • 不能包含循环、递归、switch 等复杂操作;

编译器对inline函数的处理步骤

  1. 将 inline 函数体复制到 inline 函数调用点处;
  2. 为所用 inline 函数中的局部变量分配内存空间;
  3. 将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
  4. 如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用 GOTO)。

优缺点

优点

  1. 内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度。
  2. 内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。
  3. 在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。
  4. 内联函数在运行时可调试,而宏定义不可以。

缺点

  1. 代码膨胀。内联是以代码膨胀(复制)为代价,消除函数调用带来的开销。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
  2. inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译,不像 non-inline 可以直接链接。
  3. 是否内联,程序员不可控。内联函数只是对编译器的建议,是否对函数内联,决定权在于编译器。

C++多态与虚函数的实现原理

1. 概述

虚函数

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。

虚函数表

对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。

虚函数表、虚函数、以及虚函数表的指针在内存中的位置

  • 虚函数表的指针是在实例的对象之中。
  • 虚函数表在内存中的全局区里面(每一个类只有一份虚函数表)。
  • 函数存储在内存中的代码段里面(每个个函数在内存中也只有一份)。
  • image.png

2. 虚函数表的构造过程

编译器的角度来说,B的虚函数表很好构造,D的虚函数表构造过程相对复杂。下面给出了构造D的虚函数表的一种方式(仅供参考):

  • image.png

3. 虚函数的调用过程

  • image.png

编译器只知道pb是 B* 类型的指针,并不知道它指向的具体对象类型 :pb可能指向的是B的对象,也可能指向的是D的对象。
但对于“pb->bar()”,编译时能够确定的是:此处operator->的另一个参数是B::bar(因为pb是B*类型的,编译器认为bar是B::bar),而B::bar和D::bar在各自虚函数表中的偏移位置是相等的。
无论pb指向哪种类型的对象,只要能够确定被调函数在虚函数中的偏移值,待运行时,能够确定具体类型,并能找到相应vptr了,就能找出真正应该调用的函数。

4. 多重继承

当一个类继承多个类,且多个基类都有虚函数时,子类对象中将包含多个虚函数表的指针(即多个vptr),例:

  • image.png

其中:D自身的虚函数与B基类共用了同一个虚函数表,因此也称B为D的主基类(primary base class)。

虚函数替换过程与前面描述类似,只是多了一个虚函数表,多了一次拷贝和替换的过程。

虚函数的调用过程,与前面描述基本类似,区别在于基类指针指向的位置可能不是派生类对象的起始位置,以如下面的程序为例:

  • image.png

内存分配和管理

malloc、calloc、realloc、alloca

  • malloc:申请指定字节数的内存。申请到的内存中的初始值不确定。
  • calloc:为指定长度的对象,分配能容纳其指定个数的内存。申请到的内存的每一位(bit)都初始化为 0。
  • realloc:更改以前分配的内存长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定。
  • alloca:在栈上申请内存。程序在出栈的时候,会自动释放内存。但是需要注意的是,alloca 不具可移植性, 而且在没有传统堆栈的机器上很难实现。

C++ new、delete关键字

  • new/new[]:先底层调用 malloc 分了配内存,然后创建一个对象(调用构造函数)。
  • delete/delete[]:先调用析构函数(清理资源),然后底层调用 free 释放空间。
  • new 在申请内存时会自动计算所需字节数,而 malloc 则需我们自己输入申请内存空间的字节数。

delete this

  • 保证对象是new方式分配的。
  • 保证调用delete this的成员函数是最后一个调用 this 的成员函数。
  • 保证成员函数的 delete this 后面没有调用 this 。
  • 保证delete this后不再使用该对象。

coredump

https://blog.csdn.net/sunxiaopengsun/article/details/72974548
http://man.linuxde.net/ulimit

参考文章

https://www.cnblogs.com/malecrab/p/5572730.html
https://www.nowcoder.com/questionTerminal/ae72481f412e4c709d00bdca1c78feaf
https://www.cnblogs.com/gofighting/p/5440012.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,731评论 2 9
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,304评论 8 265
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_x阅读 15,967评论 3 119
  • “蒹葭苍苍,白露为霜。所谓伊人,在水一方。” “我来自东,零雨其濛。 我东曰归,我心西悲。” 想象《诗经》里新鲜活...
    木卯丁阅读 132评论 0 1