C++开发面试基础知识点整理(超详细1)

c语言和c++的区别?

(1)c语言是面向过程的程序设计语言(面向过程就是分析出解决问题所需要的步骤、过程,然后用函数将这些步骤和过程实现);c++是面向对象的 程序设计语言(面向对象是把构成问题的事务分解成各个对象,并且考虑如何建立对象模型。c和c++最大的区别就是解决问题的方法不一样)
(2)c++中允许通过定义类自定义数据类型,并支持继承,多态
(3)c++支持函数的重载,包括操作符的重载,c不支持.
(4)c++中可以定义引用类型
(5)c++中支持bool类型
(6)c语言通过malloc和free申请和释放动态内存;c++当中通过new,delete申请和释放动态内存。
(7)c++支持默认实参
(8)c++引入了命名空间的概念。

c++和java的区别?

(1).java是面向高层的,c++是面向中间和底层的。
(2)java取消了指针,以牺牲效率带来了更高质量的代码,java是完全面向对象的,有更好的可移植性。
(3)垃圾回收的区别:c++是依靠析构函数来实现垃圾回收的,所以c和c++一定要注意内存的申请和释放。而java是通过自动回收实现的。
(4)java在web端有c++不可比拟的优势。
(5)java的接口技术代替了c++的多继承性。

面向过程与面向对象的优缺点

面向过程:性能比面向对象高,因为类的调用需要实例化,开销比较大,比较消耗资源,比如单片机,嵌入式开发,linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护。
缺点:性能比面向过程低。

const与#define的区别:

  1. const定义的常量是变量带类型,而#define定义的只是个常数不带类型;
  2. define只在预处理阶段起作用,简单的文本替换,而const在编译、链接过程中起作用;
  3. define只是简单的字符串替换没有类型检查。而const是有数据类型的,是要进行判断的,可以避免一些低级错误;
  4. define预处理后,占用代码段空间,const占用数据段空间;
  5. const不能重定义,而define可以通过#undef取消某个符号的定义,进行重定义;
  6. define独特功能,比如可以用来防止文件重复引用。

#define和别名typedef的区别

  1. 执行时间不同,typedef在编译阶段有效,typedef有类型检查的功能;#define是宏定义,发生在预处理阶段,不进行类型检查;
  2. 功能差异,typedef用来定义类型的别名,定义与平台无关的数据类型,与struct的结合使用等。#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。
  3. 作用域不同,#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。而typedef有自己的作用域。

define与inline的区别

  1. #define是关键字,inline是函数;
  2. 宏定义在预处理阶段进行文本替换,inline函数在编译阶段进行替换;
  3. inline函数有类型检查,相比宏定义比较安全;

cout和printf有什么区别?

cout<<是一个函数,cout<<后可以跟不同的类型是因为cout<<已存在针对各种类型数据的重载,所以会自动识别数据的类型。输出过程会首先将输出字符放入缓冲区,然后输出到屏幕。
cout是有缓冲输出:
cout < < "abc " < <endl;
或cout < < "abc\n ";cout < <flush; 这两个才是一样的.
endl相当于输出回车后,再强迫缓冲输出。
flush立即强迫缓冲输出。
printf是无缓冲输出。有输出时立即输出

函数调用压栈过程

1.从右向左依次压入系统栈中。
2.返回地址入栈:调用函数使用call指令调用被调函数,并把call指令的下一条指令的地址压入栈中。
3.将前栈帧进行压栈。代码区调转到被调函数的入口地址处。
4.将当前栈帧切换到新栈帧。压栈
5.将局部变量和临时变量按照定义的顺序进行压栈处理。

压栈过程图解

c++宏函数使用,例如返回较大的数:

#define MAX(a,b) ((a)>(b)?(a):(b))

strcpy函数和stncpy函数的区别?哪个函数更加安全?1. 函数原型

char* strcpy(char* strDest, const char* strSrc)
char* strncpy(char* strDest, const char* strSrc, int pos)
2.
strcpy函数: 如果参数 dest 所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。
strncpy函数:用来复制源字符串的前n个字符,src 和 dest 所指的内存区域不能重叠,且 dest 必须有足够的空间放置n个字符。

strcpy和memcpy的区别?

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

引用和指针的区别

(1).引用是对象的别名,它本身不是一个对象,不需要分配存储空间,指针本身是一个对象,需要分配内存空间,它可以指向另一个对象的地址。
(2)sizeof求引用得到的是所绑定对象的大小,而sizeof指针得到的是指针本身的大小
(3)引用必须进行初始化,而指针可以不用。所以说不存在空引用,但是存在空指针,相比较引用更安全一些。
(4)引用对一个对象进行绑定之后不能再次绑定其他对象,指针指向一个对象之后可以再次改变指向。
(5)有多级指针,但不存在多级引用。
(6)引用的创建不必调用类的拷贝构造函数。
(7)自增运算不同,引用++操作会使其绑定的值加1,指针++操作会指向下一空间的地址。
(8)作为参数时不同,传指针的实质是传值,传的是指针的地址;传引用的实质是传地址,传递的是绑定变量的地址

什么是值传递,指针传递,引用传递?

值传递:有一个形参向所属栈拷贝数据的过程,如果值传递的对象是类对象或是大的结构体对象,将耗费一定的时间和空间。

指针传递:同样会有一个形参向所属栈拷贝数据的过程,但拷贝的数据是一个固定的4字节的地址。(也是传值,传递的地址值)

引用传递:同样有上述的数据拷贝过程,但其是针对地址的,相当于为该数据所在的地址起了个别名。(传地址)

总结:从效率上将,指针传递比值传递效率高。一般主张使用引用传递,代码逻辑上更加紧凑,清晰。

new和malloc的区别:

(1)new是运算符,malloc是库函数
(2)new会调用构造函数对对象进行初始化,malloc不会,只分配内存空间。
(3)new申请分配时无需指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式的指出内存的尺寸。
(4)new分配成功后返回指定的对象类型的指针,malloc返回void*
(5)new分配失败,会抛出bad_malloc异常,malloc分配失败会返回空指针。
(6)new分配的内存通过delete释放,malloc分配的内存通过调用free()释放。

new和delete的实现原理?

对于简单类型new直接调用operator new用maclloc分配内存;
而对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;
对象分配了空间之后并构造完成,返回一个指向该对象的指针。

delete调用free函数
复杂类型则先调用析构函数
再调用operator delete;

delete是如何知道释放内存的大小的?

new[]在分配一个对象数组时,需要保存 数组的维度,做法是在分配数组空间时多分配了4个字节大小,存储数组的大小。delete时就知道需要将析构函数调用多少次了

malloc原理,brk系统调用和mmap系统调用分别是什么?

  • Malloc函数用于动态分配内存。为了减少内存碎片和系统调用的开销,malloc其采用内存池的方式,先申请大块内存作为堆区,然后将堆区分为多个内存块,以块作为内存管理的基本单位。Malloc采用隐式链表结构将堆区分成连续的、大小不一的块,包含已分配块和未分配块;同时malloc函数将可用的内存块连接为一个长长的列表的所谓空闲链表。
  • 当进行内存分配时,Malloc会沿着连接表遍历所有的空闲块,选择满足要求的块进行分配,如果超过需求,就将内存块一分为2,一块与用户申请的大小相同用于分配,另一块则是剩下来的那块返回到连接表上;
  • 调用free函数,它将用户释放的内存块连接到空闲链表上、到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链表上可能没有满足用户要求的片段了。于是,maloc函数请求延时,malloc采用边界标记法,根据每个块的前后块是否已经分配来决定是否进行块合并。
  • Malloc在申请内存时,一般会通过brk或者mmap系统调用进行申请。其中当申请内存小于128K时,会使用系统函数brk在堆区中分配,内存释放是需要等到高地址内存释放以后才能释放;而当申请内存大于128K时,会使用系统函数mmap在映射区分配,其内存可以单独释放。
  • 这两种方式分配的方式都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。

什么是内存泄漏?有哪些类型?

内存泄漏是指由于疏忽或错误造成了程序未能释放掉不再使用的内存情况。
分类:
堆内存泄漏。

对内存指的是程序运行中根据需要分配通过malloc,realloc,new等从堆中分配的一块内存,在完成是忘记了free或者delete,那么这块内存将不会再使用,就会产生内存泄漏。

系统资源泄漏

主要指程序使用系统分配的资源比如Bitmap,handle,SOCKET等没有使用相应的函数释放掉,导致资源的浪费,严重可导致系统效能降低,系统运行不稳定。

没有将基类的析构函数定义为虚函数。

当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数不会被调用,子类的资源没有正确的释放,因此造成内存泄漏。

c++的内存管理

  • 栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等。进栈和出栈都有着相应的计算机指令支持,而且分配专门的寄存器存储栈的地址,效率高,内存空间连续,但栈的内存有限。
  • 堆区(heap):一般由程序员分配释放,属于动态分配方式,若程序员不释放,程序结束时可能由操作系统回收。注意它与数据结构中的堆是两回事,分配方式类似于链表。
  • 全局区:存放全局变量和静态变量(BSS和DATA),初始化的在一块区域,未初始化的在一块区域。BSS段特点:在程序执行前BSS段自动清零,所以未初始化的全局变量和静态变量在程序执行前已经成为0.
  • 代码区:存放函数体的二进制代码
  • 只读常量区:常量的字符串存放在这里,只允许读而不允许修改。程序结束后由系统释放。

堆和栈的区别

  1. 分配方式:栈中的空间由编译器自动分配和释放,堆中的空间由程序显式地释放和分配

  2. 存储内容:栈中存储函数的参数值和局部变量;堆中存储动态对象

  3. 空间大小:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。栈的最大容量是系统预先规定好的,在Windows下,栈的大小是2M,linux是8M的空间大小(用ulimit -s查看)。因此,能从栈获得的空间较小;堆是向高地址扩展的数据结构,是不连续的内存区域。堆的大小受限于计算机系统中有效的虚拟内存。能从堆获得的空间较大。

  4. 生长方式:对于堆来说,生长方向是向上的,也就是向着内存地址增长的方向。对于栈来说,它的生长方向是向下的,是向着内存地址减小的方向增长。

  5. 分配效率:栈由操作系统自动分配和释放,(计算机在底层对栈提供支持)栈的分配效率比较高;堆的分配由C/C+函数库提供,机制复杂,堆的分配效率要比栈低很多。

原因是:对于栈来说会分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆的话,需要按照一定的算法,在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间,还需要系统功能区增加程序数据段的内存空间。

  1. 碎片问题:对于堆来说,频繁的new/delete操作势必会造成内存空间的不连续,从而造成大量的碎片;栈不会产生空间碎片。

什么是段错误?什么时候发生?

段错误通常发生在访问非法内存地址的时候。
例如以下情况发生:
使用野指针
试图修改字符串常量的内容

什么是野指针?如何检测内存泄漏?

野指针:指向内存被释放的空间或者没有访问权限的内存的指针。
野指针的成因有三种:
1.指针变量没有初始化
2.在指针被释放空间之后没有置空
3.指针越界

static关键字的作用

(1)定义局部静态变量:当局部变量离开作用域后,并没有销毁,而是仍然驻留在内存中,只不过我们不能再对它进行访问,直到该函数再次被调用,值不变。
(2)定义全局静态变量:使变量在本文件内有效,改变变量的生命周期,在整个程序运行期间一直存在。
(3)定义静态函数:static函数仅在本文件内有效。
(4)静态变量和全局变量存储在静态数据区。在静态数据区中所有的字节默认值为0x00。
c++中类成员声明
(5)定义类的静态成员:静态成员数据与类本身向关联,而不是与对象相关联。因而对类的对象只有一份拷贝。还有就是static类对象必须在类外进行初始化。
(6)定义静态成员函数:属于类不属于对象。不与任何对象绑定在一起,这个函数不接收this指针,因而只能访问类的static成员变量。还有就是static成员函数不能被virtual修饰,因为static成员不属于任何对象,所以加上virtual没有意义。

如何实现在一个静态函数中使用类的动态成员(包括成员函数和成员变量)

1.通过类的静态对象来调用。比如单体模式中,静态函数可以通过类的全局唯一实例来访问动态成员函数。
2.将类的对象作为参数传递给该静态函数,然后在静态函数中引用这个对象,并调用其动态方法。

c语言和c++语言静态变量什么时候进行初始化?

在c语言中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到c语言中无法使用变量对静态局部变量就行初始化,在程序运行结束之后,变量所处的全局内存会被全部回收。

在c++中,初始化在执行相关代码时才会进行初始化,主要是由于c++引入对象后,要进行初始化必须执行相应的构造函数和析构函数,在构造函数或者析构函数中经常会需要进行某些程序中进行的特定操作,并非简单的分配内存。

const关键字的作用

(1)定义const对象,阻止变量的值被改变,const对象必须被初始化。
(2)定义常量引用,不能被用作修改它所绑定的对象的值。
(3)定义常量指针(顶层const),指针本身是个常量,常量指针必须初始化,而且一旦初始化,则它的值就不能改变了。(即它的指向不可变)
(4)定义指向常量的指针(底层const),此指针不能用于改变其所指对象的值。
(5)定义const成员函数,表明其是一个常函数,不能修改类的成员变量,如果以引用形式返回*this,那么返回类型将是常量。(常量对象,常量引用或常量指针都能只能调用常量成员函数。)
(6)定义函数形参为常量引用,表明函数不会修改实参的值。

对于const成员函数和const对象之间的关系理解:

1.const成员函数,表明其是一个常函数,不能修改类的成员变量,类的常对象只能访问类的常成员函数。
2.如果返回值为const类型,以使得其返回值不为“左值”。
3. const成员函数可以访问非const对象的非const数据成员、const数据成员,也可以访问const对象内的所有数据成员;
4.非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不可以访问const对象的任意数据成员;
4. 一个没有明确声明为const的成员函数被看作是将要修改对象中数据成员的函数,而且编译器不允许它为一个const对象所调用。因此const对象只能调用const成员函数。

const Stock & Stock::topval (2.const Stock & s) 3.const

1.处const:确保返回的Stock对象在以后的使用中不能被修改
2处const:确保此方法不修改传递的参数 S
3.处的const:保证此方法不修改调用它的对象,const对象只能调用const成员函数,不能调用非const函数。

指针和const的用法剖析:

当const修饰指针时,由于const的位置不同,它的修饰对象就会有所不同。

1.int *const p2 常量指针,表示const修饰的是p2,p2只能指向一个固定的地址,但可以通过p2来修改这个变量的值。
2.int const p1或者const int p1 指向常量的指针,const修饰的是p,表明p的值不可改变,也就是说指针所指的值不可改变。但指针可以改变自己的指向。
3.const int *const p,指针的指向和指向的值都不可改变。

mutable关键字:

如果需要在const成员方法中修改一个成员变量的值,应该怎么做?
需要将这个成员变量修饰为mutable.即用mutable修饰的成员变量不受const成员方法的限制。

volatile关键字详解

volatile关键字可以保证线程 安全,阻止编译器过度优化。从而提供对特殊地址的稳定访问。
可以做到两件事
保证变量的内存可见性,阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回。
保证代码的有序性,阻止编译器调整操作volatile变量的指令顺序。

什么是变量内存可见性?

在多线程的环境下,某个共享变量如果被其中的一个线程给修改了,其他线程能够立即知道这个共享变量已经被修改,当其他线程要读取这个变量的时候,最终会去内存中读取,而不是从寄存器。

例子:
两个线程访问同一变量,编译器如果为了提高访问速度,把变量放入寄存器中,就会出现问题。
x=0;
Thread 1 Thread 2
lock(); lock();
x++; x++;
unlock(); unlock();

执行步骤可能会呈现如下情况。
Thread1 读取x的值到寄存器1
然后使寄存器1里的值++;(暂不放回)
Thread 2读取x的值到寄存器2
然后使寄存器2的值++
Thread 2写回内存,x=1;
Thread 1写回内存, x=1;
可见,正确的加锁,也不能保证多线程安全。

volatile用在如下的几个地方:

  1. 中断服务程序中修改的供其它程序检测的变量需要加volatile;
  2. 多任务环境下各任务间共享的标志应该加volatile;
  3. 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

什么是函数指针?函数指针的声明方法?为什么要有函数指针?

函数指针就是指向一个函数地址的指针,通过它可以调用这个函数。函数的类型是由其返回的数据类型和其参数列表共同决定的,而函数的名称则不是类型的一部分。

特别要注意的是函数指针的声明和返回指针类型的函数要区分开。
int (*pf)(const int&,const int&);函数指针
int *pf(const int& const int&); 返回指针的函数

面向对象的易维护性体现在什么地方?

体现在封装上。
封装就是把具体实现细节隐藏起来,只留下简单的接口供使用者调用。
封装有两个重要的优点:
(1)确保用户代码不会无意间破坏封装对象的状态。
(2)被封装的类的具体实现细节可以随时改变,而无需调整用户级别的代码。

封装详解:

  • 一旦把数据成员定义成private的,类的作者就可以自由的修改数据了。当实现部分改变时,我们只需要检查类的代码本身以确认这次改变有什么影响;换句话说,只要类的接口不变,用户代码就无须改变。如果数据时public的,则所有使用了原来数据成员的代码都可能失效,这时我们必须定位并重写所有依赖于老版本实现的代码,之后才能重新使用该程序。
  • 把数据成员的访问权限设成private还有另外的一个好处,这么做能防止由于用户的原因造成数据被破坏。如果我们发现有程序缺陷破坏了对象的状态,则可以有限的范围内定位缺陷:因为只有实现部分的代码可能产生这样的错误。因此,将查错限制在有限的范围内将能极大的降低代码修正的难度。

c++不能重载的运算符

不能重载的运算符只有5个:
. (成员访问运算符)
* (成员指针访问运算符)
:: (域运算符)
sizeof (长度运算符)
?: (条件运算符)

c++强制类型转换。

先说一下c风格类型转换的缺陷。
可以支持任意类型之间的转换,比如可以把一个const指针转换成指向非const对象的指针。把一个基类对象的指针转换成指向一个派生类对象的指针。不安全,而且不易查找。

  • static_cast 静态类型转换
    任意具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
    用法:static<目标类型>(标志符)
  • dynamic_cast 子类和父类之间的多态类型转换。
    特别适用于以下情况:就是我们想使用基类对象的指针或引用指向某个派生类操作并且该操作不是虚函数。
    当无法使用虚函数时,使用它(RTTI运算符),但与虚成员函数相比,存在更大的风险:程序员必须清楚的知道转换的目标类型并且检查类型转换是否成功。(如我们不能使一个指向猫类型的基类指针,转换成指向一个狗类型的指针,转换不成功,抛出一个bad_cast异常)
  • const_cast 去掉const性质转换,将常量对象转换成非常亮对象。
    目标类型只能是指针或者引用,改变其对象的底层const。
  • reinterpret_cast 重新解释类型转换
    它会在运算对象的位模式提供较低层次的重新解释。(与c语言强制转换效果相同)
    这种转换较危险,它会真正意义的进行类型的转换。如我们可以用static_cast将子类对象赋给父类指针是允许的。但是不可以将父类对象赋给子类指针。reinterpret_cast可以进行强制转换赋值达到。

什么是智能指针管理内存资源,RAII

RAII,意思是资源获取即初始化。也就是说在构造函数中申请分配资源,在析构函数中释放资源。
因为在c++语言机制保证了,当一个对象创建的时候,自动调用构造函数,当对象超出作用域的时候会自动调用析构函数。所以,我们应该用类管理资源,将资源和对象的生命周期绑定。

(1)shared_ptr类允许多个指针指向同一个对象。
一般的使用方法搭配make_shared函数使用,返回指向对象的shared_ptr指针。

它通过引用计数记录有多少个其他shared_ptr指向相同的对象。无论何时我们拷贝一个shared_ptr,计数器都会递增,当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时,计数器就会递减。

一旦一个shared_ptr的计数器变为0时,它就会自动释放自己所管理的对象,并释放它所占用的内存。

(2)unique_ptr 某个时刻只能有一个unique_ptr指向一个给定对象。因此不支持拷贝和赋值操作。对于避免资源泄漏特别有用。
但可以利用reset()或release()函数转交控制权。当一个unique_ptr被销毁时,它所指的对象也就被销毁了。
值得一提的是,虽然unique不能拷贝或者赋值,但是却可以拷贝或者赋值一个即将要销毁的unique_ptr,比如return一个unique_ptr。

(3)weak_ptr 是一种弱引用,指向shared_ptr所管理的对象。
设计的目的是为了配合shared_ptr协助工作,提供了对管理对象的一个访问手段。它主要有以下的特性和功能:

  • 将它绑定到shared_ptr不会改变引用计数。
  • 可以解决shared_ptr相互引用时的死锁问题,如果两个shared_ptr互相引用会导致引用计数不可能下降为0,资源不释放,如果其中一个改为weak_ptr,当析构时就可以使引用计数为0.
  • 由于对象可能不存在,所以我们不能使用weak_ptr,直接访问对象,而必须lock(),此函数检查weak_ptr指向的对象是否仍然存在。
    一旦shared_ptr释放的话,它也会释放。
  • 使用成员函数use_count()可以查看当前引用计数,expired()判断引用计数是否为空

(4)auto_ptr 它和unique_ptr很像,区别是我们不能从容器中保存auto_ptr,也不能从函数中返回auto_ptr.
auto_ptr< string> p1 (new string ("I reigned lonely as a cloud.”));
auto_ptr p2;
p2 = p1; //auto_ptr不会报错.
此时不会报错,p2剥夺了p1的所有权,但是当程序运行时访问p1将会报错。
缺点:存在潜在的内存崩溃问题。

程序编译的过程:

编译的过程分为预处理,编译,汇编,链接四个过程。
预处理:消除注释,替换宏,处理预处理指令,包含库文件,生成.i文件。
编译:词法分析,语法分析,语义分析,优化处理 ,生成.s文件
汇编:把汇编语言翻译成目标机器指令,生成目标文件.o文件
链接:将目标文件链接生成可加载,生成可执行文件

include头文件的顺序以及双引号""和尖括号<>的区别?include头文件的顺序区别:

如果在文件a.h中声明一个在文件b.h中定义的变量而不引用b.h。那么要在a.c文件中先引用b.h,后引用a.h,否则汇报变量的类型会声明错误。

双括号和尖括号的区别:编译器预处理阶段查找头文件的路径不一样
对于双括号包含的头文件,查找文件的路径为:

  • 当前头文件目录
  • 编译器设置的头文件目录
  • 系统变量指定的头文件目录

对于尖括号包含的头文件,查找文件的目录为:

  • 编译器设置的头文件目录
  • 系统变量指定的头文件目录。

C++的异常情况:

语法错误。比如,变量未定义,关键字拼写错误等
运行错误:比如内存不足,栈溢出,非法访问内存等,会在运行时出错,导致程序崩溃。为了有效的处理程序运行时错误,C++中引入异常处理机制来解决此问题。
C++的异常处理机制:
由三个模块组成:try(检查)、throw(抛出)、catch(捕获)。
执行一个函数的过程中发现异常,可以不用在本函数内立即进行处理,而是抛出该异常,让函数的调用者直接或者间接处理该问题。

发布了40 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/suoyudong/article/details/104886882
今日推荐