1.为什么C++支持函数重载,而C语言不支持函数重载呢?
答: 这与C/C++的调用约定和名字修饰规则有关。
C语言:vs Add ----->(编译后) _Add
C++:vs Add ----->(编译后) ?Add@@YAHNH@Z 函数参数不同会导致编译后的函数名不同
因为同名函数没办法区分,而C++只要函数参数不同,修饰出来的名字也不同,就支持了重载。
2.什么是函数重载?
答:函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
注:
- 函数重载与否与函数的返回值类型是否相关没有关系。
- C语言不支持函数重载
- 函数重载后,调用函数时可能会出现以下情况:
(1)如果类型完全匹配,则直接调用。
(2)如果类型不能完全匹配,则编译器会尝试进行隐式类型转换,转化后如果有合适的类型的函数则直接调用,否则转换之后没有合适类型则报错。有时候,隐式类型转换可能存在不止一个函数合适,那怎么办?编译器直接报错。
3.C++函数重载底层是怎么处理的?
答:Linux下,采用gcc编译完成后,函数名字后面的修饰没有发生改变。采用g++编译完成后,函数名字的修饰发生变化,编译器将函数参数类型信息添加到修改后的名字中。
4.C++中能否将一个函数按照C语言风格来编译?怎么做?
答:可以。在函数前加extern“C”。
5.extern与static的区别。
- extern 可以使变量在不同的文件共享,static限制了变量的作用域,只能在本文件中使用。extern 和static不能修饰同一个变量。
- extern 是用来声明变量的,最好在头文件中使用。static是定义变量,一般将它放在原文件。
- 全局变量默认为extern
- 函数或变量可以声明多次,但定义只有一次。
6.引用和指针的区别。
答:在概念上,引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
在底层实现上,引用也有空间,引用是按照指针的方式来实现的。所以在底层上引用与指针实际上没有区别。
俩者的不同点:(概念,使用,特性)
- 引用在定义时必须初始化,指针则没有要求。
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
- 没有NULL引用,但有NULL指针。
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占 4个字节) 。
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。
- 有多级指针,但是没有多级引用。
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。
- 引用比指针使用起来相对更安全
注:传值传递最慢,传地址和传引用差不多。如果以引用的方式作为函数的返回值类型,不能返回函数栈上的空间,如果要返回,必须要比函数的声明周期长,即函数结束了,返回的实体依然存在。
7.函数的调用过程是怎样的?
答:如果以引用的方式作为函数的返回值类型,不能返回函数栈上的空间。如果要返回必须要比函数的生命周期长,即函数结束了,返回的实体依然存在。
浅析函数的调用过程_xy294636185的博客-CSDN博客_函数调用过程
8.const在c语言和c++中是一样的吗?
答:不一样。
在c++中,const修饰的内容是一个常量,而且还具有宏替换的效果。并且替换发生在编译时。
在C语言中,const修饰的表示不能被修改的。
注:在c++中,#define 定义出来的成为宏;在C++中#define定义的可能是宏常量也可能是宏变量。虽然使用它也能定义常量但是更加建议使用const定义常量,这样更加安全。
9.宏有什么优缺点?
- 优点: 1.增强代码的复用性。 2.提高性能(预编译的时候展开,不需要每次运行时载入,可能提高程序的运行效率)。3.方便程序的修改(一次就可以改变参数)。
- 缺点: 1.不方便调试宏。(因为预编译阶段进行了替换,不会进行正确检查,不能调试) 2.导致代码可读性差,可维护性差,容易误用。 3.没有类型安全的检查 。4.宏函数可能有副作用(忘记代括号导致逻辑错误)。5.宏表达式中不能出现递归定义,这点区别于函数,因为宏只做简单的文本替换,且只替换一次,如果出现递归定义,就会无法被完全替换,导致后续编译时原宏名被当作函数。
10.内联函数一定会展开吗?
答:不一定。编译器在debug模式下,编译器一般不会将内联函数展开(默认情况下,个人可以通过设置编译器来让它展开)。
11.C++有哪些技术替代宏?
- 常量定义换用const
- 函数定义换用内联函数(内联函数只能在定义它的文件中调用其他文件中不可以)
12.面向过程与面向对象的区别
- 面向过程:是一种以过程为中心的编程思想。都是以什么正在发生为主要目标进行编程。面向对象:是一类以对象作为基本程序结构单位的程序设计语言,指用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。
- C语言的结构体中只能放变量,不能放函数。C++中的结构体不止能放变量,还能放函数。
面向过程:
- 优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。
- 缺点:不易维护、不易复用、不易扩展。
面向对象:
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 。可维护性表现在三个方面:可理解性。可测试性和可修改性。
- 缺点:性能比面向过程低。
13.struct和class的区别(俩个都可以用来定义类)
- struct为了兼容C语言,所以C++中的struct可以当成结构体去使用。C++中struct还可以用来定义类,struct定义的类实际上是一种自定义类型。class定义的类,类中的数据称为类的属性或成员变量,class中内容称为类体或类的成员。
- struct的默认权限是public,class的默认访问权限为private。(访问限定符只在编译时使用,当数据映射到内存后,没有任何访问限定符上的区别)
- 模板的typename可以用class替代,但不能使用struct替代。
14.什么是内联函数?
答:inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,用函数体替换函数的调用。没有函数压栈的开销,内联函数提升程序运行的效率。
注:
- 在Debug模式下,编译器一般不会将内联函数展开。
- 内联函数是一种以空间换时间的做法,省去调用函数的开销。代码很长或者有循环/递归的函数不适合作为内联函数。
- 内联函数对编译器而言只是一个建议,编译器会自动优化,可能会忽略掉内联。
- 内联函数只能在当前文件中使用。不建议内联函数的声明和定义分离,分离会导致链接错误。因为内联函数被展开没有函数地址了,链接就会找不到。
15.什么是封装?
答:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装实际上是一种管理。
16.C++如何实现封装特性?
答:类+访问权限。
注:访问权限:public(公有),protected(保护),private(私有)。
17.空类的大小为多少?为什么?
答:主流编译器(vs/g++)中的空类大小为1。空类看见来什么都没有,既没有成员变量也没有成员函数,但是实际上不是什么都没有,编译器会生成6个默认成员函数。
注:
- 没有成员变量只有成员函数的类大小也是1。
- 实际上6个默认成员函数也不一定会生成,如果编译器需要则生成,如果不需要则不会生成。那么什么时候编译器需要?什么时候有不需要呢?
18.为什么编译器将空类的大小设置为1而不是0?
答:假设空类的大小为0,先创建一个类(不是空类)c1,再创建2个空类c2、c3,此时从内存角度看c1,c2,c3就存储在同一个位置。3个类的地址就相同,也就是说c1,c2,c3就是同一个对象。这和程序矛盾。
19.this指针存在哪里?
答:vs中this指针保存在栈中。this指针的指向是不可以被修改的。(类类型*const this)
注:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即不需要用户来传递,编译器主动完成。
- this指针的类型:类类型*const 。
- this只能在成员函数中使用。
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况有编译器通过ecx寄存器自动传递,有时候使用参数压栈的方式传递(这与调用约定有关),不需要用户传递。
20.this指针可以为空吗?
答:可能会为空。如果成员函数是通过指针调用,this指针有可能会为nullptr。当this指针指向nullptr时,this就是nullptr。
注:当this指针为nullptr时,只要在成员函数中没有访问成员变量则代码不会崩溃,如果访问成员变量,则代码一定会崩溃。