JITc 编译器哪个好如何找到'发出调用的变量的类型'对应的类型对象

个人整理免费分享,不可用于商业用途转载请注明出处!

但是有同学反应闲鱼上有人盗卖此免费分享资料,还有好多同学买了所以希望大家多多点赞评论收藏,提高这份资料被搜索引擎搜索到的概率我就不加水印影响大家使用了。

今年是第一次整理此系列度不好控制,后面可能会继续优化造福後面的同学大家加油!

需要pdf直接打印版,可在公众号"程序员宝藏"回复复试上岸获取(会持续更新)

在复习过程中我用心查阅并整理了在考研复试面试中可能问到的大部分问题,并分点整理了***可以直接理解背诵并加上自己的语言润色!极力推荐打印下来看,效率更高!

声奣:一些边边角角的没有收集毕竟是考研面试,不是笔试这样也能减轻大家的负担!

此系列一共有8篇:编程语言篇|数据结构篇|操作系統篇|组成原理篇|计算机网络篇|数据库篇|软件工程篇|计算机专业英语篇(还未全部完成,敬请期待,你们的支持和关注是我最大的动力!)

需要408电子书2021蝂,可在公众号"程序员宝藏"回复408电子书获取

需要408初试视频2021版可在公众号"程序员宝藏"回复408视频获取

需要复试机试视频,可在公众号"程序员寶藏"回复机试必过获取

加油大家都可以上岸!!!让我们一起努力!!!


C语言面向过程,重点在于算法和数据结构C程序的设计首先考慮的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控 制)

C++语言是面向对象语言,首先考虑嘚是如何构造一个对象模型让这个模型能够契合与之对应的 问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制 它在C的基础上添加了面向对象、模板等现在程序设计语言的特性。拓展了面向对象设计的内容如类、继承、虚函数、模板和容器類等等,使之更加符合现代程序设计的需要

C++是C语言的继承,它既可以进行C语言的过程化程序设计又可以进行以抽象数据类型为特点的基于对象的程序设计(泛型编程),还可以进行以继承和多态为特点的面向对象的程序设计(面向对象编程)支持类、封装、继承、多態等特性。

面向对象编程:面向对象是一种对现实世界理解和抽象的方法、思想通过将需求要素转化为对象进行问题处理的一种思想。

:类定义了事物的属性和它可以做到的(它的行为)一个类的方法和属性被称为“成员”。一个类所包含的方法和数据描述一组对象嘚共同属性和行为类是在对象之上的抽象,对象则是类的具体化是类的实例。

封装性:封装使数据和加工该数据的方法(函数)封装為一个整体把对象的设计者和对象的使用者分开,使用者不必知晓行为实现的细节可以增加安全性。

继承性:继承性是子类共享父类の间数据和方法的机制一个类直接继承其它类的全部描述,同时可修改和扩充可以增强代码的复用性。

多态性:对象根据所接收的消息而做出动作同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性使具有不同内部结构的对象共享相同的外部接口。可以增加扩展性

1、指针和变量的自增自减有什么不同?

答:变量的自增自减是改变变量的值指针的自增自减是改变指针的指向哋址。

2、宏定义与操作符的区别

答:宏定义是C++的预处理命令之一,它是一个替换操作不做计算和表达式求解,不占内存和编译时间

3、虚函数与纯虚函数的特点?

答:虚函数必须是基类的非静态成员函数其访问权限可以是protected或public;纯虚函数是虚函数的一个子集,含有纯虚函数的类就是抽象类它不能生成对象。

4、如何使用纯虚函数

答:纯虚函数用来定义没有意义的实现,用于抽象类中需要交给派生类具體实现的方法

5、引用与值传递的区别?

答:值传递传递的是一个值的副本函数对形参的操作不会影响实参的值;引用传递传递的是引鼡对象的内存地址,函数对形参的操作会影响实参的值实参的值会随着形参的值得改变而改变。

6、指针与引用的区别

答:(1)引用无需解引用,指针需要解引用;(2)引用在定义时被初始化一次之后不可变,指针可变;(3)引用不能为空指针可以为空;(4)程序为指针变量分配内存区域,而引用不需要分配内存区域所以指针自增操作是指针变量的自增,引用自增操作是变量值的自增

7、面向对象與面向过程的区别?

答:面向过程是一种以过程为中心的编程思想以算法进行驱动;面向对象是一种以对象为中心的编程思想,以消息進行驱动面向过程编程语言的组成:程序=算法+数据;面向对象编程语言的组成:程序=对象+消息。

8、面向对象的特征是什么

答:面对对潒的3个要素:封装,继承多态。面向对象中所有对象都可以归属为一个类

9、类与结构体有什么区别?

答:(1)结构体存储在栈中类嘚实例化可以存储在栈中,也可以存储在堆中;(2)结构体的执行效率比类要高;(3)结构体没有析构函数类有析构函数;(4)结构体鈈可以继承,类可以继承

10、C++覆盖与隐藏概述?

答:(1)覆盖指的是在子类和父类中存在函数名、参数均相同的函数,并且父类的该函數为虚函数;(2)隐藏指的是在子类与父类中存在函数名相同、参数不同的函数,此时无论父类函数是否为虚函数父类函数都会被被隱藏,或者存在函数名、参数均相同的函数此时只有当父类函数不为虚函数时,父类函数才会被隐藏

11、C++支持参数个数不确定的函数吗?

答:C++可以通过隐藏参数机制支持参数不确定的函数

12、什么是内联函数?

答:在类声明的内部声明或定义的成员函数叫做内联(inline)函数在内联函数内不允许有循环语句和switch语句。

13、什么是静态函数如何使用静态函数?

答:静态函数是用static修饰符修饰的函数静态函数没有this指针,只能访问静态变量类中如果函数调用的结果不会访问或者修改任何对象数据成员,这样的成员声明为静态成员函数比较好

14、函數重载及作用域?

答:函数重载是指在相同作用域下具有相同名称而不同参数列表的多个函数。

15、什么是函数模板

答:函数模板技术昰指使用了模板技术定义了参数化类型的非成员函数,这使得程序能够使用不同的参数类型调用相同的函数

答:类模板是使用模板技术的類,描述了能够管理其他数据类型的通用数据类型类模板技术通常用于建立包含其他类型的容器类(队列、链表、堆栈等)。

17、什么是泛型编程

答:泛型编程就是以独立于特定类实现的方式编写代码,针对不同的类型提供通用的实现

18、C++如何实现泛型编程?

答:C++中泛型編程的实现是使用C++中的模板技术来实现的主要是设计函数模板和类模板。



首先应该清楚Java 是由 C++发展而来的,保留了 C++的大部分内容其编程方式类似于 C++。但 Java 的句法更清晰、规模更小、更易学Sun 公司曾对多种程序设计语言进行分析研究,取其精华去其糟粕最终推出了 Java。Java从根夲上解决了C++的固有缺陷形成了新一代面向对象的程序设计语言。

Java是一种解释性(或者说半解释半编译)语言意味着其在执行时会被“翻译”为二进制形式,也就是java跑得时候必须有人(jvm)去解释它(现在的Java语言其执行方式已经不仅仅是解释执行方式了,即时c 编译器哪个恏(JITC、just-in-time compiler)技术和原型编译技术的出现大大提高了J***A的运行效率)而C++则是编译语言,意味着程序只能在特定操作系统上编译并在特定系统上運行也就是说C++一步到位成机器语言的。

**Java 没有指针的概念**在 C/C++中,指针操作内存时经常会出现错误。而在Java中是没有指针这一概念的因此也有效地防止了一系列由指针引起的操作层失误(如指针悬空所造成的系统崩溃),更有利于 Java 程序的安全

Java是一种内存安全型语言,意菋着大家可以为给定数组分配任意参数即使超出范围也只会返回错误提示。C++更为灵活但代价是一旦分配的参数超出资源范围,则会引起错误甚至严重崩溃

**Java不支持多重继承。**多重继承它允许多父类派生一个子类。也就是说一个类允许继承多个父类。尽管多重继承功能很强但使用复杂,而且会引起许多麻烦编译程序实现它也很不容易。所以 Java 不支持多重继承但允许一个类实现多个接口。可见Java 既保留了 C++多重继承的功能,又避免了 C++的许多缺陷

Java 是完全面向对象的语言,所有方法和数据都必须是的一部分除了基本数据类型之外,其余类型的数据都作为对象型数据例如,对象型数据包括字符串和数组类将数据和方法结合起来,把它们封装在其中这样每个对象嘟可实现具有自己特点的行为。而 C++将函数和变量定义为全局的然后再来调用这些函数和变量,从而增加了程序的负担此外,Java 还取消了 C/C++Φ的结构和联合使编译程序更加简洁。

**Java 自动进行无用内存回收操作不再需要程序员进行手动删除。**Java 程序中所有的对象都是用 new 操作符建竝在堆栈上的这个操作符类似于 C++的“new”操作符。当 Java 中一个对象不再被用到时无须使用内存回收器,只需要给它添加删除标签无用内存的回收器便利用空闲时间在后台运行。而 C++中必须由程序释放内存资源这就增加了程序员的负担。

Java 不支持操作符重载操作符重载被认為是 C++的突出特征。操作符重载就是把操作符(比如’+,-*,/'这些运算符)赋于新的意义 来完成更为细致具体的运算等功能。要实现操作符偅载就要使用操作符重载函数,而运用函数就肯定会存在各种限制条件以及特殊情况特殊情况就需特殊处理,因此操作符重载还是比較繁琐的Java语言是走“简洁风”的,因此为了保持Java语言的简洁性便毅然抛弃了操作符重载这一功能,但是为了避免舍本逐末的情况Java语訁还是可以通过来实现操作符重载所具有的功能的。

C/C++在编译过程中都有一个预编译阶段即预处理器。预处理器为开发人员提供了方便但增加了编译的复杂性。Java 允许预处理但不支持预处理器功能,因为 Java 没有预处理器所以为了实现预处理,它提供了引入语句(import)但咜与 C++预处理器的功能类似。

Java 不支持缺省参数函数而 C++支持 在 C 语言中代码组织在函数中,函数可以访问程序的全局变量后来C++增加了类,提供了类算法该算法是与类相连的函数,C++类方法与 Java 类方法十分相似由于 C++仍然支持 C语言,所以 C++程序中仍然可以使用 C 的函数结果导致函数和方法混合使用,使得 C++程序混乱而Java 没有函数(准确说叫方法)。作为一个比 C++更纯的面向对象的语言Java 强迫开发人员把所有例行程序包括茬类中。事实上用方法实现例行程序可激励开发人员更好地组织编码。

C 和 C++不支持字符串变量在 C 和 C++程序中使用**“Null”终止符代表字符串的結束。在 Java 中字符串是用类对象(String 和 StringBuffer)来实现的在整个系统中建立字符串和访问字符串元素的方法是一致的。Java 字符串类是作为 Java 语言的一部汾定义的而不是作为外加的延伸部分。此外Java 还可以对字符串用“+”进行连接操作。

“可怕”的 goto 语句是 C 和 C++的“遗物”它是该语言技术仩的合法部分。goto语句也称为无条件转移语句通常与条件语句配合使用,用来实现条件转移 构成循环,跳出循环体等功能但是,在结構化程序设计中一般不主张使用goto语句 以免造成程序流程的混乱,使程序的可读性变差,增加程序调试的难度 Java 不提供 goto 语句,虽然Java指定 goto 作为關键字但不支持它的使用,这使程序更简洁易读

在 C 和 C++中,有时会出现数据类型的隐含转换这就涉及了自动强制类型转换问题。例如在 C++中可将一个浮点值赋予整型变量,并去掉其尾数Java 不支持 C++中的自动强制类型转换,如果需要必须由程序显式进行强制类型转换。

java侧偅于大型企业级应用开发C++侧重于底层应用开发。Java是Android开发领域的王者因此移动开发者无疑应该选择它作为项目基础。另外Java也常见于Web及桌面应用乃至服务器端应用。

C++更接近机器语言因此其软件运行速度更快且能够直接与计算机内存、磁盘、CPU或者其它设备进行协作。另外C++也能为游戏提供良好的运行性能。

除 了“能够让应用程序处理存储於DBMS 中的数据“这一基本相似点外两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术而 接口并且基于微软的.NET 体系架构。众所周知.NET 體系不同于COM 体系 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持

***:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。

***:不是两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的

25. main 函数执行以前,还会执行什么代码***:全局对象的构造函数会在main 函数の前执行。

26. 描述内存分配方式以及它们的区别?
1) 从静态存储区域分配内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在例如全局变量,static 变量
2) 在栈上创建。在执行函数时函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放栈内存分配运算内置于处理器的指令集。
3) 从堆上分配亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少嘚内存程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定使用非常灵活,但问题也最多

***:struct 的成员默认是公囿的,而类的成员默认是私有的struct 和 class 在其他方面是功能相当的。

从 感情上讲大多数的开发者感到类和结构有很大的差别。感觉上结构仅僅象一堆缺乏封装和功能的开放的内存位而类就象活的并且可靠的社会成员,它有智能服 务有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在 的!)时,你也许应该使用 struct 关键字否则,你应该使用

28.当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少如果不是零,请解释一下c 编译器哪个好为什么没有让它为零(Autodesk)***:肯定不是零。举个反例如果是零的话,声明一个class A[10]对象数组而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了

29. 在8086 汇编下,逻辑地址和物理地址是怎样转换的(Intel)
***:通用寄存器给出的地址,是段内偏移地址相应段寄存器地址*10H+通鼡寄存器内地址,就得到了真正要访问的地址

常量有数据类型,而宏常量没有数据类型c 编译器哪个好可以对前者进行类型安全检查。洏对后者只进行字符替换没有类型安全检查,并且在字符替换可能会产生意料不到的错误

34.类成员函数的重载、覆盖和隐藏区别?***:
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(4)virtual 关键字可有可无
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)鈈同的范围(分别位于派生类与基类);
(4)基类函数必须有virtual 关键字
c.“
隐藏
”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名但是参数不同。此时不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)
(2)洳果派生类的函数与基类的函数同名,并且参数也相同但是基类函数没有virtual 关键字。此时基类的函数被隐藏(注意别与覆盖混淆)

39.文件Φ有一组整数,要求排序后输出到另一个文件中


(1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)

43. 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数

KMP算法效率最好,时间复杂度是O(n+m)

函数:一个命名的代码块通过調用函数执行响应的代码。函数可以有0个或者多个参数通常会产生一个结果。

重载:同一个名字可以对应几个不同的函数

返回类型 函数洺字 (参数列表){
函数或者指向函数的指针(实参列表)
//返回类型 函数名 (参数列表)
//函数或者指向函数的指针(实参列表)
  1. 隐式的定义並初始化它的形参因此调用fact函数的时候,首先创建一个val的int变量然后将它初始化为调用时所用的实参5

  2. 当遇到return语句时,结束函数体的执行同时,将return语句的值返回给调用者

实参时形参的初始值。他们依据位置一一对应虽然位置一一对应,但是却没有规定他们的求值顺序

实参类型必须和形参类型一一匹配。这个和初始化变量的要求一模一样

形参列表可以为空,这样就只有一个小括号

同时,为了和c语訁兼容也可以在空形参列表的位置,写上void

形参列表以逗号分隔每个元素跟变量声明一样,注意就算多个变量类型,一样也要分开寫。如下:

形参属于函数体内部的局部变量,超出这个范围访问失败

  1. void类型,表示函数不返回任何值
  2. 函数不能返回数组类型,和函数類型但是可以返回指向他们的指针

作用域:名字可见的范围
生命周期:对象存在的时间

函数的函数体,就是一个语句块这个语句块构荿一个作用域,形参和函数体内部定义的变量都在这个作用域中

形参和函数体内部定义的变量称为局部变量。之所以称为局部是因为超出函数体之后,这些将不复存在

局部对象还会隐藏外层作用域的同名声明。

在函数体内部的对象分为以下几种:

  1. 自动对象:把只存茬于块执行期间的对象,称为自动对象

自动对象的创建:从变量的定义语句开始。一旦程序的控制路径到达变量的定义语句则创建该對象。

自动对象的销毁:一旦到达定义语句所在作用域的末尾则销毁该对象。

形参是一种自动对象函数开始时,为形参申请存储空间因为形参的作用域为函数体,因此函数一旦结束,则形参被销毁

而形参的初始化,是通过实参:用实参的值初始化形参。而其他茬函数体内部定义的对象如果没有进行初始化,那么他们执行默认初始化因此对于内置类型来说,如果没有初始化那么他们的值就昰未定义的。

  1. 局部静态变量:将局部对象用static关键字修饰就变成了局部静态对象。

局部静态对象的初始化:从定义语句开始
局部静态对潒的销毁:程序终止时,销毁

count_calls内部的ctr使用了static关键字修饰,因此是一个局部静态变量当第一次调用count_calls函数时,将初始化ctr变量然后自增ctr。當后续几次调用count_calls时因为已经初始化了ctr,所以不再初始化而是,直接自增ctr这样ctr一直保存有count_calls被调用的次数

函数在使用之前必须先声明,函数的声明跟函数定义一样。唯一的区别是:将函数体用分号代替注意此处,的分号并不是代替了空的语句块,而是表示语句的结束

又因为在声明中没有函数体,所以形参名也就用不上所以声明中可以省略形参名。但是加上形参名会更好因为,这样有助于程序嘚理解

函数声明也叫做,函数的原型因为声明包括了函数的三要素:返回类型,函数名形参类型。

这三要数可以唯一标识一个函数類型

通常将函数声明放在头文件中,然后在需要用到的地方include这个头文件即可。这样可以保证所有需要用到这个函数的声明都是一致嘚。

随着程序规模的变大程序员希望将程序,按照逻辑进行划分c++提供了这种功能,这种功能称为分离式编译.分离式编译可以将程序分開到不同的文件中每个文件单独编译。这样程序员就可以将不同的逻辑放在不同的文件中每个文件单独编译。

举个例子(书中例子):

使用下面的命令同时编译两个文件

不同的c 编译器哪个好,分离式编译使用的步骤有细微差别可参考c 编译器哪个好手册。

参数传递分為两种:引用传递和值传递

将实参的值,复制给形参他与非引用类型变量的初始化一样。修改形参不会对实参有任何影响。他们是兩个不同的变量

注意:当需要传递的形参类型是指针类型时实际还是进行的值传递,即将一个实参指针复制给了形参。他们时两个不哃的指针只不过指向了同一个地址而已

ip = 0;//只改变了ip这个局部变量,实参为改变

熟悉c的程序员常常使用指针类型的形参访问函数外部的对潒。在c++语言中建议使用引用类型的形参代替指针类型

引用形参和上面的引用变量类似,可以让函数改变引用所绑定的对象

i = 0;//会改变i所绑萣对象的值

因为i时引用类型,所以当改变i的值就相当于改变i所绑定对象的值。

  1. 拷贝大类型对象时比较耗时,因此可以使用引用

  2. 对于有些类型来说不支持拷贝操作,因此在函数穿参中必须使用引用累心给,比如(IO类型)

因为string对象可能会比较大为了避免无所谓的复制,此处的函数形参定义为引用类型同时,又因为不会修改内容定义了const类型。

使用引用形参还可以返回额外的信息

一个函数只能返回一個值如果一个逻辑需要返回多个值,可以使用引用形参将需要返回的结果,放入引用形参中

下面逻辑,希望返回c第一出现的位置哃时,统计其次数因为需要返回两个参数,所以将c出现次数通过引用形参返回

跟变量的初始化一样,当实参用于初始化形参时其顶層const将会被忽略。

调用fcn时既可以传入const int,也可以传入int忽略掉顶层const 可能产生意向不到的结果:

因为顶层const被忽略,所以上面两个相当于同一个萣义

尽量使用const引用

定义成普通的引用,常会引入下面的不便:

  1. 让使用者认为里面的值可以被改变
  2. 不能使用const对象,字面值或者需要类型转换的对象,进行传参

因此,常常将形参定义成const 引用

当形参时数组时有如下两个限制:

  1. 使用数组的时候,会将其转换成指针
//尽管形式不一样但是这三个print函数是等价的。
//每一个函数都有一个const int*类型的形参

如果给实参是一个数组自动将这个数组转换成一个指向数组首元素的指针。

注意:以数组作为形参的函数也必须确保使用数组的时候不会越界

正是由于数组以指针的形式被传递出去,所以数组的大小僦需要另外的方式传递给函数下面有几种常见的方式传递给函数:

这种方式表示,在数组本身内容中有表示数组结束的标记,比如c风格字符串他以空字符作为结尾,这样一旦遇到空字符就可以表示达到了末尾

这种方式的唯一要求是:数组的内容和标记不能混淆。

向函数传递数组的首元素和尾后元素的指针例子如下:

其中begin和end是标准库提供的支持,这样就可以将一个数组的范围提供给一个函数了

显礻的传递一个表示数组大小的形参

形参和普通的变量一样,可以定义为数组的引用此时,引用形参绑定到了对应的实参上面也就是绑萣到了数组上面。

注意:arr两边的括号必不可少

跟普通的数组一样传递多维数组,实际上传递是的指向多维数组首元素的指针。因为多維数组实质上是数组的数组,所以首元素就是一个指向数组的指针。数组第二维的大小就是数组类型的一部分不能够胜率:

将上面函数的matrix为,一个指向数组的指针这个数组有10int类型。

没有什么特殊不再做笔记

6.2.6 含有可变形参的函数

有时候,不知道函数需要多少个形参此时可以使用可变形参的函数,可变形参的函数有两种方法:

如果实参数量未知但是类型,相同我们可以使用initializer_list类型的形参。它提供嘚操作如下:

注意:initialize_lise对象中的元素是常量值无法对其进行改变

省略符形参应该仅仅用于c和c++通用的类型。特别应该注意的是大多数类类型的对象在传递给省略符形参时都无法正确拷贝

省略符形参只能出现在形参的最后一个位置,它的形式无外乎如下两种:

对于有类型的形參则跟其他普通的形参一样,会进行相应的类型检查省略符形参对应的实参无须进行类型检查。在第一种形式中形参声明后面的逗號是可选。

此种用法还不会带后续完善加强

return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。

return语句有两种形式:

6.3.1 无返囙值的函数

无返回值的return语句只能用在返回类型是void的函数,而void函数不一定非要return语句举例如下:

//此处无须显示的return语句

6.3.2 有返回值得函数

如果┅个函数的返回类型不为空,那么这个函数的每一条return
语句都需要返回一个值并且这个返回值类型必须与函数的返回类型相同,或者隐式哋转换成函数的返回类型

//错误:控制流可能尚未返回值,就结束了函数的执行 //c 编译器哪个好可能检查不出这一错误

for循环内部的return语句是错誤的因为他没有返回值,c 编译器哪个好能够检查这种错误

for语句之后没有提供return语句在上面的程序中,如果string对象是另外一个的子集则函數在执行完for循环之后还将继续执行,显然应该有一个return语句来专门处理这种情况。c 编译器哪个好可能检查不出这种错误一旦检查不出来,这种行为是未定义的

返回一个值得方式和初始化一个变量或者形参的方式完全一样:返回值用于初始化调用点的一个临时变量,该临時量就是函数调用的结果

不要返回局部对象的引用或者指针

函数完成之后,所占用的存储空间也随之被释放因此,局部变量将被销毁如果返回局部变量的指针,或者引用那么这个指针指向的对象,或者这个引用绑定的对象是不存在的

函数的返回类型决定了函数返囙的是左值还是右值。调用一个返回引用的函数得到的是左值其他返回类型得到的是右值。

上面函数的所有return语句都返回一个用大括号括起来的,列表

这就跟使用列表进行对变量初始化一样。所以对于内置类型来说花括号之内只能有一个值。

前面有介绍过:如果函数嘚返回类型不是void则必须返回一个值。

唯一的例外是:允许main函数没有return语句直接返回如果控制语句达到了main函数的结尾而且没有return语句,则c 编譯器哪个好将隐式地插入一条返回0的return语句

main函数的返回值,被认为程序执行状态的指示器返回0表示成功,非0值表示执行失败其中非0值嘚具体含义依机器而定。

为了使返回值与机器无关cstdlib头文件定义了两个预处理变量,可以使用这两个预处理变量表示成功或者失败

因为數组不能拷贝,因此函数只能返回数组的指针或者数组的引用。

  1. func是一个函数它的形参为int
  2. 数组的元素为int类型

上面的写法对于新手来说有點不易理解,有几下几种写法可以更加容易理解

将返回类型放在最后然后以前函数类型的位置,使用一个auto关键字

注意:decltype并不负责将数组類型转换成对应的指针类型所以decltype的结果是一个数组,要想表示指针还需要加上一个星号*

重载函数:同一作用域中的几个函数名相同但昰形参列表不同。

注意:main函数不能重载

对于重载函数来说:他们应该在形参类型后者形参数量上有所不同。

上面两组都是相同的函数洇为他们的形参类型和形参的数量并没有变化。

在第二组中形参的类型本质上是同一种类型

这两组声明中,第二个都跟第一个是同样的聲明因为,顶层const会被忽略掉因此,对于含有顶层const的形参和没有顶层const的形参,无法区别开来

上面两组函数,都是不同的函数因为c 編译器哪个好可以通过实参是否为常量来决定调用那一个函数。

如果我们希望我们传递给这个函数的实参是非常量,并且返回类型也希朢是非常量上面的函数有所局限,所以可以在新增一个函数这个函数是上面这个函数的一个重载版本:

函数匹配:将函数调用与一组偅载函数中的某个函数关联起来的过程。它又叫做重载确定

调用重载函数时,有三种可能的结果:

  1. c 编译器哪个好找到一个最佳匹配的函數并调用它
  2. 找不到任何与调用匹配的函数,此时c 编译器哪个好发出无匹配的错误信息
  3. 找到多个函数可以匹配但是每一个匹配都不是最佳匹配,此时c 编译器哪个好发出二义性调用的错误

记住:如果在内层作用域中声明的名字,它将隐藏外层作用域中声明的同名实体

//不恏的习惯:通常来说,在局部作用域中声明函数不是一个好的选择

因为c++中名字查找在类型检查之前,所以当调用print函数时,先找到了局蔀作用域中声明的函数然后再进行类型的检查。发现3.14时将会将其转换成int类型,然后调用局部作用域中的函数声明

6.5 特殊用途语言特性

紸意:一旦一个形参被赋予了默认值,那么这个形参之后的所有形参都必须有默认值

在传递参数的时候,带有默认实参的形参可以不鼡传递实参,也可以传递实参

在一个作用域中一个形参只能被赋予一次默认实参。例子如下:

通常应该在函数声明中指定默认实参,並将该声明放在合适的头文件中

局部变量不能作为默认实参除此之外,只要表达式的类型能转换成形参所需的类型该表达式就能作为默认实参。

用作默认实参的名字在函数声明所在的作用域解析而这些名字的求值过程在发生在函数调用时:

sz wd = 100; //隐藏了外层定义的wd,但是没囿改变默认值

对于一些频繁调用的小的函数而言可以使用内联函数,以此来减少函数调用产生的跳转消耗

一般来说内联机制用于优化規模较小,流程直接频繁调用的函数。

不过很多c 编译器哪个好都不支持内联递归函数

constexpr函数:能用于常量表达式的函数。

constexpr函数:函数的返回类型及所有形参的类型都是字面值类型而且函数体中必须有且只有一条return语句

执行改初始化时,c 编译器哪个好把对constexpr函数的调用替换成其结果值为了能够在编译时随时展开,constexpr函数被隐式地指定为内联函数

constexpr函数体内也可以包含其他语句只要这些语句运行时不执行任何操莋就行。例如可以包含空语句,类型别名已经using声明等。

//如果cnt是一个常量表达式则scale为constexpr函数,否则不是

因此从上面可以知道:constexpr函数不┅定返回常量表达式

把内联函数和constexpr函数放在头文件

和其他函数不一样,内联函数和constexpr函数可以在程序中多次定义毕竟,c 编译器哪个好要想展开函数仅有函数声明是不够的还需要函数的定义。不过对于某个给定的内联函数或者constexpr函数lai9shuo它的多个定义必须完全一样。基于这个原洇内联函数和constexpr函数通常定义在头文件中。

如果expr为假则输出信息并终止程序。如果为真assert什么也不做

在开发阶段,让这个assert生效而在正式的软件版本中,让assert失效这依赖NDEBUG预处理变量

如果定义了NDEBUG则assert什么也不做。默认状态下没有定义NDEBUG

这样只需要在正式版本中,定义NDEBUG即可就鈳以忽略掉assert的运行时开销。

除此之外还可以更具NDEBUG自己定义相应的调试代码。例子如下:

上面函数中如果没有定义NDEBUG,则执行#ifndef和#endif之间的代碼如果定义了NDEBUG,这些代码将被忽略掉

c++除了定义了__func__之外还定义了下面:

__FILE__ 存放文件名字的字符串字面值
__LINE__ 存放当前行号的整形字面值
__TIME__ 存放文件编译时间的字符串字面值
__DATE__ 存放文件编译日期的字符串字面值

在重载函数中,函数的匹配有下面的几个过程

确定候选函数和可行函数

第┅步:选定本次调用对应的重载函数集合,集合中的函数称为候选函数

候选函数具备两个特征:1.与被调用的函数同名;2.其声明在调用点鈳见。

第二步:从候选函数中选出能被这组实参调用的函数这些函数称为可行函数。

可行函数有两个特征:1.形参数量与实参数量相同;2.烸个形参类型与实参类型相同或者实参类型能够转换成形参类型。

第三步:从可行函数中选择与本次调用最匹配的函数这一步的过程為:逐一检查函数调用提供的实参,寻找形参类型与实参类型最匹配的可行函数类型越接近,匹配越完美

    类型越接近匹配越完美因此,最佳匹配为:

现在思考下面的调用的匹配过程:

3.最佳匹配逐一对每个实参进行类型检查
对于第一形参来说,最佳匹配为

对于第二个形參来说最佳匹配为

无法判断哪一个可行函数最佳,因此c 编译器哪个好报,二义性错误

为了确定最佳匹配c 编译器哪个好将实参类型到形参类型转换划分成了几个等级,具体排序如下:

1·精确匹配,包括如下情况:

实参类型和形参类型相同

实参从数组类型或者函数类型转換成对应的指针类型

向实参添加顶层const或者从实参中删除顶层const

2.通过const转换实现的匹配

3.通过类型提升实现的匹配

4.通过算术类型或者指针类型转换實现的匹配

5.通过类类型转换实现的匹配

注意:所有的算术类型的转换级别都一样例如,int向unsigned int的转换并不比int向double的类型转换级别高:

在第一次調用中传入的是const对象,不能将const对象绑定到普通的引用中所以,最佳匹配为

在第二次调用中传入的是一个非const对象,而非const对象可以绑定const引用也可以绑定到非const引用。然后用非常量对象绑定给const引用需要进行一次类型转换,而非const引用形参的函数则是精确匹配,所以最佳匹配为这个函数

指针也有上面类似的行为

函数类型由返回类型和形参类型决定。

可以声明一个指针指向函数,格式如下:

  1. 这个指针指向┅个函数这个函数的返回类型为bool

注意:pf两端的括号必不可少

在指向不同函数类型之间的指针,不能相互转换但是可以给函数指针赋值nullptr戓者值为0的整形常量表达式,表示该指针没有指向任何一个函数:

//自动将函数lengthCompre转换成指向该函数的指针

可以使用类型别名来简化这种写法:


不能返回函数但是能够返回指向函数的指针

  1. 它的返回类型是一个指针,
  2. 这个指针指向一个函数
  3. 指向的函数的形参为int*,int
  4. 指向的函数的返囙类型为int

上面的写法较为繁琐,可以简化为下面的写法:

PF f1(int);//正确:PF是指向函数的指针f1返回的是指向函数的指针
F f1(int);//错误:F是函数类型,f1不能返囙函数类型
F* f1(int);//正确:显示地指定返回类型为函数指针

注意:跟decltype作用在数组一样decltype作用在函数上面时,返回的时函数类型
因此如果想要声明函数指针,则应该多加一个星号*

上面难免错误遇到错误的请指出,谢谢

我要回帖

更多关于 编译器 的文章

 

随机推荐