43、面向对象的三个特征
多态、封装、继承
44、C++语言的优缺点
优点:
c++是面向对象的程序设计,在高级语言中,处理运行速度最快,而且还兼容了c语言
C++语言十分灵活,功能十分强大,它的优点在于性能和类层次结构设计
C++十分严谨、精确和数理化,标志定义很细致
C++语法思路层次分明、相呼应,语法结构是显示的,明确的
缺点:
语言过度复杂和标准库的过度苍白
45、同样是面向对象的语言,c++和jAVA相比有什么区别
1、JAVA的运行速度比C的执行速度慢上约20倍
2、JAVA所有的东西都必须置入一个类
3、JAVA中没有作用域范围运算符
4、JAVA没有预处理功能的详细介绍
5、JAVA里没有c++那样的指针,只有引用,JAVA中所有的对象都是分配在堆上,
6、JAVA采用了一种单根式的分级结构,所有对象都是从根类Object统一继承的,而c++可用来实现多重继承和多重继承
7、JAVA有垃圾回收机制,有了垃圾回收,就不会产生内存泄露,而c++需要用析构函数,delete来回收内存
46、C++和C语言有什么区别(具体可参考c到c++的升级)
1、C语言是面向结构的,c++是面向对象的
2、在C++中局部变量可以在一个程序块内在任何地方声明,在c中,局部变量必须在程序块的开始部分,即所有操作之前
3、C语言中是通过函数名来查找函数的,在c++里对函数有重载作用,根据各种函数的声明来查找
4、在c中,可以调用main函数,但是在c++中不能调用main函数
5、Register关键词在c语言中不能用取地址符来获取寄存器的地址,在C++中可以用取地址符,使用了取地址符就默认了取消了register的类型
6、在c++中可以用const修饰成员和成员方法,修饰成员的时候要进行初始化,修饰成员方法的时候只能使用不能修改,const调用const,不能调用非const,而在c中const一般用来修饰函数的形参
7、内存的分配和释放:在c语言中用malloc和free来分配和释放内存,在c++中使用的是new和delete来分配和释放内存和初始化
8、在c++中引入了“引用”这个概念,给变量起别名,还引用了命名空间,限定变量的作用域,使变量名不冲突,而在c里则没有这些概念。
9、在c++中可以对函数进行重载,而在c中无法对函数进行重
47、引用是什么?使用引用的时候有什么注意点吗
引用就是给变量起个名字,对应用的操作与变量直接操作效果完全相同。
注意点:
1、申明一个引用的时候,一定要对引用初始化,实际上是把值赋给了引用所绑定的对象
2、引用声明完成后,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表明该引用名是目标变量名的一个别名
3、引用本身不是一种数据类型,因此引用本身不占存储单元,系统也不会给引用分配存储单元。不能建立数组的引用。
4、引用可以用作函数的返回值,可以将函数放在赋值运算左边,但是不能返回局部变量的引用
48、将引用作为函数参数有哪些特点
(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作:而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本:如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间好。
(3)使用指针作为函数的参数虽然能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用“*指针变量名”的形式进行运算,这很容易发生错误且程序的阅读性差:另一方面,在主函数的调用点处,必须用变量的地址作为形参。而引用更容易使用,更清晰。
49、指针和引用的区别
1、引用是直接访问,而指针是间接访问
2、引用是对象的别名,不分配内存空间,而指针会分配内存空间
3、引用定义时一定要初始化,而指针不一定需要初始化
4、引用不是对象,不能定义指向引用的指针,指针是对象,可以定义指向指针的引用
5、引用一经初始化就不能引用其他变量,而指针可以。
尽可能使用引用,不得已使用指针
50、什么时候需要用引用
使用引用,不会调用对象的拷贝构造函数
在实际应用中,引用一般用作函数形参或函数的返回值
51、什么是内联函数?他的主要作用是什么?如何声明内联函数
编译器将代码量小,但使用频繁的函数做inline函数,内联函数是指用inline关键字修饰的函数。在类内声明部分定义的函数被默认成内联函数。
作用:内联函数在编译的时候将不进行函数的调用,提高了效率
内联函数只能是代码很少很简单的函数,因为如果一个很大很复杂的函数即使设为内联,编译器也将自动设置该函数为非内联。
52、内联函数和宏函数的区别
内联函数是用空间换时间,省去了函数调用的时间,宏函数是用时间换空间,对宏函数进行简单的替换
内联函数在调用的时候,要求实参和形参一致,内联函数会先对实参表达式进行求值,然后传递给形参,而宏函数的实参只是简单的替换成形参
内联函数是在编译的时候,在调用的地方将代码展开的,而宏函数是在预处理的时候进行替换的
在c++中建议使用内联函数取代带参数的宏函数
53、函数重载的条件
函数重载:相同的作用域,函数名相同,但是函数的参数不同,称为函数的重载
条件:
函数的参数个数不同,参数的类型不同,参数的顺序不同都可以用来做函数的重载,但是函数的返回值不可以用来做重载的条件
C++为了支持重载,用extern c来辨别是按c还是c++的编译方法进行编译
54、重载和重写(override)的区别
重载:函数名相同,函数的参数不同,不能只有返回值不同,可以有不同的访问修饰符;可以抛出不同的异常;存在于父类和子类和同类之间
重写:参数列表和返回类型必须与重写的函数相同
访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。
存在于父类和子类之间
55、命名空间的作用
限定变量的作用域,使变量名不冲突
56、四种类型转换运算符的区别
1、static_cast<>() 是用于基本数据类型之间的转换、有继承关系的类对象之间和类指针之间的转换,没有运行时类型检查来保证转换的安全性。
2、Const_cast<>() 是除去const属性
3、Reinterpret_cast<>() 是把一个指针转换为整数或将整数转换为指针
4、Dynamic_cast<>() 主要是将基类对象指针或引用转换成继承类指针,实现了类层次间的上行转换和下行转换,还可以用于类之间的交叉转换,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的; 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
57、类和struct的区别
类声明的时候默认为私有类,结构体默认为公有的结构体
类继承的时候,默认的是私有继承,结构体继承的时候默认的是公有继承
58、什么是this指针,this指针的作用
1、this指针只能在一个类的成员函数中调用,它表示的是当前对象的地址。
全局函数,静态函数,友元函数都不能使用this指针
This指针的作用:成员函数对成员变量的引用实际是通过this指针访问的,成员函数需要访问当前对象,也可以通过this指针。
在类的非静态成员函数中返回对象的本身时候,直接用return *this(常用于操作符重载和赋值、拷贝等函数)。传入函数的形参与成员变量名相同时,例如:this->n = n (不能写成n=n)
注意点如下:
1、 当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,又隐含使用this指针。
2、.当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在的对象的指针。
3、 在C++中,this指针被隐含地声明为: X *const this,这意味着不能给this指针赋值;
4、 由于this并不是一个常规变量,所以,不能取得this的地址。
5、this指针是在创建对象前创建.this指针放在栈上,在编译时刻已经确定.并且当一个对象创建后,并且运行整个程序运行期间只有一个this指针.
59、为什么需要this指针
因为this作用域是在类的内部,自己声明一个类的时候,还不知道实例化对象的名字,所以用this来使用对象变量的自身。在非静态成员函数中,编译器在编译的时候加上this作为隐含形参,通过this来访问各个成员(即使你没有写上this指针)
60、一定要在构造函数的初始化列表中初始化的有哪
被const修饰的成员只能在初始化列表中进行初始化,必须在每个构造函数的初始化列表里初始化
引用成员的初始化也只能在初始化列表中进行初始
若基类里有对象成员的时候,在基类的构造函数的初始化列表中要调用对象的构造函数。
在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。
61、类定义中的public、private和protect有什么区别?
public:它是类与外部的接口,外部的函数都可以访问公有类型的数据和函数
Private:只允许本类中的函数访问,而类外的函数无权访问
Protect:与private相似,区别是在继承的时候
62、构造函数的特点有哪些
1、构造函数的名字和类名一样
2、不能定义构造函数的返回类型
3、构造函数一般被声明为公有函数,否则不能被显示调用;构造函数被声明为私有函数时,有特殊的用法
4、构造函数可以被重载
5、全局的构造函数优先于main函数执行
63、析构函数的特点有哪些
1、析构函数与类型一样,只在前面多了~
2、析构函数也不能定义返回类型
3、析构函数没有参数,不能被重载
64、Base temp = 5;的过程
1、调用转换构造函数,创建一个临时对象 Test(5)的对象
2、将临时对象赋值给temp对象
3、临时对象析构
65、函数带默认参数的使用方法
默认值定义从左到右,如果某个参数没有默认值,则他的左边也不能有
有定义有声明的时候,声明时带默认参数,则定义里就不必使用。
66、默认生成的函数有哪些
构造函数,析构函数,拷贝构造函数,赋值构造函数,取值运算符
67、如何修改被const修饰的对象和成员函数
1、可以用关键词mutable,可以修改const对象和const成员对象
2、可以使用const_cast<>()强制转换,把const类型的对象转换为非const的对象
68、什么情况下会调用拷贝构造函数
1、使用一个已知对象来初始化一个新对象
2、函数返回一个类对象,会调用拷贝构造函数
3、函数的形参是类的对象,会调用拷贝构造函数
69、深拷贝和浅拷贝的区别
系统默认的构造函数为浅拷贝构造函数,浅拷贝是两次指向的是同一块内存,若其中一个对象析构,另一个对象析构时将会发生段错误
深拷贝:程序在调用拷贝构造函数的时候,重新分配了内存,所以不会有段错误发生,所以一般要自定义拷贝构造函数
特殊情况:当类里有指针对象的时候,要对这个指针进行深度拷贝,=运算符要进行深拷贝
70、什么是多继承和多重继承
多继承:一个派生类继承多个基类
多重继承:一个派生类继承一个基类
71、为什么需要运算符重载
我们用运算符重载来把正常的+、-、*、/、<、> 用于自定义数据类型的对象
72、运算符重载的规则
1、不允许发明新的运算符
2、不能改变运算符操作对象的个数
3、运算符被重载之后优先级和结合性都不会改变
4、不能重载运算符有:域运算符(::)、条件运算符(?:)、直接成员访问运算符(.)、类成员指针引用运算符(*.)、sizeof运算符sizeof
友元函数和成员函数的选择问题:
1、单目运算符用成员函数,双目运算符用友元函数
2、以下一些双目运算符不能用友元函数:=、()、[]、->
3、类转换运算符只能以成员函数方式重载
4、流运算符只能以友元方式重载
73、运算符重载的作用
直观自然,提高程序的可读性
体现了C++的可扩充性
另一种函数调用方式
74、New运算符的三种格式以及其区别
1、operator new:分配空间,可以被重载,但是不会调用构造函数
2、New operator:调用operator new分配内存空间,调用相应的构造函数
3、Placement new:不分配空间,在已有的空间上调用operator new,在调用构造函数
75、在虚继承的时候,基类和派生类之间构造函数的调用顺序
基类中如果有成员对象,先调用成员对象的构造函数,接着是基类的构造函数;若派生类中有成员对象,先调用成员对象的构造函数,再是派生类的构造函数,析构函数与这个顺序相反
76、如何解决二义性
用作用域的限定符
用虚继承来解决二义性:由最远派生类的构造函数通过调用虚基类的构造函数进行初始化,其他派生类的调用无效
77、友元机制的作用
1、破坏封装性
2、非类的成员函数访问类的私有成员
78、友元机制的注意点
1、破坏封装性,不要频繁使用
2、不能通过对象来调用友元函数,友元函数不属于类,也不属于对象
3、友元函数不受public、protect、private的限制
4、生命周期不受类的限制
79、什么是纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
如:virtual void funtion1()=0
80、多态的实现方式有哪几种
函数重载、运算符重载、虚函数、模板
其中重载为静态多态、模板为动态多态
81、多态的两个必要条件
1、 基类中必要要有虚函数,且在派生类中有实现虚函数
2、 基类的指针要指向派生类或者基类的引用调用派生类
82、多态的作用
1、 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。
2、派生类的功能可以被基类的方法或引用变量所调用,这叫向下转换,可以提高可扩充性和可维护性。
83、C++中静态成员有何作用,他的特点是什么?
静态成员不属于某个类,可用于不同类的所有对象共享
静态成员属于内存中,不实例化不能分配内存,所以静态成员不能访问非静态成员,但是非静态成员可以直接访问静态成员
必须在类外进行初始化
84、为什么析构函数需要设置为虚析构函数
想要通过调用基类的析构函数释放其派生类的析构函数,层层回调,释放资源
85、六大组件分别是什么
容器,分配器,迭代器,适配器,算法,函数对象
86、六大组件之间的关系
容器通过分配器来分配空间,迭代器访问容器中的数值,获取容器中的数据,不同的迭代器之间需要适配器来适配,迭代器在访问数据的时候使用的算法来实现
87、各种容器之间的优缺点
vector:优点:不确定内存的大小数组的连续存储,可以像数组动态操作
随机访问方便,用支持[]操作符或者vector.at()
缺点:不确定内存进行插入删除操作效率低
只能在vector进行最后的push和pop,不能在头部进行vector.at()
当动态的添加数据超过vector默认分配的代销需要进行重体分配的,拷贝函数释放
list:优点:不使用连续内存完成动态操作
在内部方便的进行插入和删除操作
可在两端进行push和pop
缺点:不能进行内部的随机访问
相对于vector占用内存多
Deque:优点:随机访问方便
可内部方便的进行插入和删除
可在两端进行push和pop
缺点:占用内存多
Set: 优点:不包括重复的元素,
set内部使用平衡二叉树实现的,便于元素的查找
88、各种容器的实现原理
Vector:数组
Deque:模拟的动态数组
List:双向链表
Map:红黑树,平衡二叉树
Set:平衡二叉树
89、栈和队列的特点
栈:是先进后出,只允许在一端进行插入和删除
队列:先进先出,允许在两端进行插入和删除
90、什么是反向迭代器,与迭代器的区别是什么
反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++运算将访问前一个元素,而--运算则访问下一个元素。
c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素
c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置
c.begin() 返回一个迭代器,它指向容器c的第一个元素
c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置
遍历
vector<int>::reverse_iterator rit;
for(rit = v1.rbegin(); rit != v1.rend(); rit++)
{
cout<<*rit<<endl;
}:
91、选择容器遵循的原则是什么
1、需要高效的随机存取,不在乎插入和删除效率,使用vector
2、需要大量的插入和删除,不关心随机存取,使用list
3、需要随机存取,关心两端数据的插入和删除,使用deque
4、存储一个数据字典,要求方便的根据key找value,map是较好的选择
5、要查找一个元素是否在某集合内,使用set存储这个集合比较好
92、Map类容器存放键值对的方法
有三种:
假设map<string,int>m
1、m[“hello”] = 1;
2、m.insert(pair<string,int>(“hello”,1));
3、M.insert(map<string,int>::value_type(“hello”,1));
93、键值对是什么?
可以根据一个键值获得对应的一个值,键值不能重复,键值是唯一的,对于值来说不要求唯一性
94、模板的作用
模板是一种参数化的多态工具,采用模板编程,是可以为各种逻辑功能相同,数据类型不同的程序提供了一种代码共享的机制
95、函数模板和类模板有什么区别
函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。即函数模板允许隐式调用和显式调用而类模板只能显示调用
96、函数对象和函数指针的区别
函数的对象可以看成是()的重载,函数对象和函数指针定义的时候不一样,使用的时候是一样的,但是函数对象可以携带附加数据,函数指针就不行了。要让一个函数既接受函数指针,也接受函数对象,那最方便的就是函数模板了
97、什么叫做设计模式
模式就是在一定的环境下解决问题的方法,包括三个基本要素:问题,方案和环境。
设计模式就是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解、保证代码的可靠性。设计模式使代码编制真正的工程化
98、设计模式遵循的原则有哪些
开放封闭原则、依赖倒置原则、接口隔离原则、里氏替换原则、合成复用原则、迪米特法则
99、设计模式分为哪个种类
1、创建型模式,包括单例模式、原型模式、建造者模式、抽象工厂模式、工厂方法模式
2、结构型模式,包括代理模式,享元模式,装饰者模式、适配器模式、桥接模式、组合模式、外观模式
3、行为型模式,包括模板方法模式、命令模式、责任链模式、策略模式、中介者模式、观察者模式、备忘录模式、访问者模式、状态模式、解释器模式
100、单例模式的作用
单例模式可以保证一个类中只有一个实例对象,并且该实例容易被外界访问,从而方便对实例个数的控制并节约系统资源。
101、单例模式的实现方法
构造函数私有化,提供一个全局的静态成员方法,在类中定义一个静态指针,指向本类对象的静态变量指针
102、建造者模式和工厂模式的区别
1、工厂模式不考虑对象的组装过程,Factory模式不考虑对象的组装过程,而直接生成一个我想要的对象。
2、Builder模式先一个个的创建对象的每一个部件,再统一组装成一个对象。
3、Factory模式所解决的问题是,工厂生产产品。
而Builder模式所解决的问题是工厂控制产品生成器组装各个部件的过程,然后从产品生成器中得到产品。
103、Extern c的作用
在c++中按照c的编程风格来编译和连接的
104、New delete和malloc free的联系与区别
1、操作对象不同:new/delete是c++的运算符,会调用构造函数和析构函数;而malloc/free是库函数而不是运算符
2、Malloc和new都可以分配内存,free和delete都可以释放内存,但是new在分配内存的同时还可以初始化
3、New是自动分配的,malloc需要定义字节数
4、New是安全的,malloc则不是
105、Const和#define相比,有什么优点
1、有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试
2、编译器可以对const进行类型安全检查。而对#define只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
106、C++函数中值的传递有哪几种方式
值传递
指针传递
引用传递
107、派生类如何访问基类的私有成员
1.在基类的声明中增加保护成员,将基类中提供给派生类访问的私有成员定义为保护成员。
2.将需要访问基类私有成员的派生类成员函数声明为友元。
108、不能被继承的成员函数有哪些
析构函数、构造函数,赋值函数、拷贝函数
109、函数的向上转型适用于哪种情况,向下转型适用于哪种情况
向上转型:是指派生类指向基类,一般是只有继承的情况下的
向下转型:是基类的指针指向了派生类的对象,一般发生多态的情况下
110、什么是常指针,什么是指向常变量的指针
常指针就是指向常量的指针,顾名思义,就是用来指向常量的,
如const int *p或者int const *p
用常指针也可以用来指向一般变量,这时候可以通过一般变量的变量名来修改变量的值
指针常量是指的指针本身就是一个常变量,一经赋初值就不可以被更改。
如:int *const p = &i;
C++规定只能用指向常变量的指针来指向常变量,不能用普通指针指向常变量
总之:看被const修饰的是什么,如果紧跟着const的是*p这种,就是指向的是常量,其指向内存空间的值不可变,其地址可变;如果紧跟着const的是p这种,其对应的内存空间不可变,但是其空间内存储的值可变,就是可通过*p来改变
111、函数指针和指针函数区别
根据定义的左右法则可知:
函数指针是指指针指向函数的内存空间,如:(*p)(int,int)
指针函数是指函数的返回值是一个指针类型的变量,如*fun(int,int)
112、C++会自动为类产生的四个缺省函数是什么
默认构造函数、默认析构函数、赋值函数、拷贝构造函数
113、赋值运算符合拷贝运算符之间的关系
类类型的变量需要使用拷贝构造函数来完成整个赋值过程
拷贝构造函数用已存在的对象创建一个相同的新对象。而赋值运算符用已存在的对象赋予一个已存在的同类对象。
拷贝构造函数发生在创建对象时,只发生一次拷贝赋值可以重复发生;
114、构造函数和析构函数可以被重载吗?为什么
构造函数可以被重载,析构函数不能被重载
构造函数可以有很多个且带参数
析构函数只有一个且不带参数
115、如何定义和实现一个类的成员函数为回调函数
回调函数就是调用函数指针的函数,一个函数将自己的函数地址传给另一个函数做形参,并调用该函数所指向的函数,这个函数就称为回调函数
在c++中的实现方法:
1、可以使用友元函数
2、可以使用static的静态成员函数
116、Main函数执行以前,还会执行什么代码
在c++中,全局对象的构造函数会在main函数之前执行
核心会运行专门的启动代码,启动代码会在main()之前完成所有的初始化工作,这其中包括了全局对象的初始化,这个初始化代码就是在Runtime中的Startup代码
在程序执行时,系统会调用Startup,完成函数库初始化,进程信息设立,I/Ostream产生,以及对static对象的初始化等动作,然后Startup调用main函数,把控制前交给main函数,main()函数执行完毕之后,控制权交回Startup,进行反初始化动作
117、堆和栈的区别
堆:有程序员分配释放,调用malloc等函数分配空间,调用free或delete释放空间,变量未初始化的时候,系统初始化为0,先进先出,堆的空间约等于虚拟内存大小-1GB
栈:由系统自动分配,空间一般4MB左右,先进后出,一般存局部变量,函数参数自动变量,未初始化的时候,会随机赋值
118、什么时候需要预编译
C编译系统,在对程序进行通常的编译之前,首先进行预处理,为编译做预备工作的阶段,可以放在程序的任意位置
119、什么时候需要使用“常引用”
利用引用提高程序的效率,又要保护传递给函数的数据不再函数中被改变,就应使用常引用。
声明方式:const 类型&引用名=目标变量名
如:const int &a = a;
120、Const关键字的作用
Const修饰的变量为只读变量,定义的时候要对变量进行初始化,一般用来修饰函数的形参,不能通过修改变量名来修改函数的值,但是通过变量的地址来改变变量的值
对于指针来说,既可以指定指针本身为const,也可以指定指针所指的数据为const,或者二者同时指定为const
Const既能修饰成员,也能修饰成员方法,修饰成员的时候,只能在初始化列表中初始化,并且只能使用不能修改,要放在函数的后面,有时候必须指定其返回值为const类型,以使其返回值不为“左值”
Const修饰对象的时候,只能调用const,不能调用非const
121、多态里什么叫做静态关联,什么叫做动态关联
确定调用的具体对象的过程称为关联
在编译的时候确定调用的虚函数属于哪一类称为静态关联
在执行的时候把虚函数和类对象绑定在一起,称为动态关联
静态关联在多态里包括函数重载和运算符重载
动态关联在多态里包括虚函数
122、捕获异常时有哪些注意点
1、抛出的是一个对象的时候,在catch接受的时候,编译器会拷贝构造一个对象的副本,若是catch那边也是用对象来接,就是会拷贝两次
2、析构函数不能抛出,构造函数可以抛出异常,因为析构函数在抛出自己未经处理的异常的时候,将会导致调用标准库的terminate函数,而默认的terminate函数将调用abort函数,强制从整个程序中退出;如果一个构造函数抛出异常之后,他的析构函数得不到执行,需要手动销毁在异常抛出前已经构造的部分
3、抛出的如果是局部变量,会进行栈展开,在栈上的局部变量会被销毁,但是如果栈展开中的局部变量有指针,并且该指针在之前已经用new分配了空间,有可能导致内存泄露
4、获取派生类的catch应在获取基类catch的前面,否则派生类的异常会被基类捕捉到
5、捕获异常的void*不能放在catch前面,抛出指针通常是个坏主意,最好不要抛出指针
6、...的异常捕获应在最后面
123、为什么需要对文件进行二进制读写
用二进制读写文件的时候,文件本身的内容和你编写程序时用函数读到的内容完全一致,就是将内存中的样子原封不动的搬到了文件中,而文本文件是将每一个数据转换成字符写入到文件中,他们在大小和布局上都有着区别,二进制文件是读出来直接用,而文本文件还存在一个“翻译”的过程,相比较而言,二进制文件的可移植性更好。
124、模板函数和函数模板的联系和区别
函数模板不是函数,不能被执行
置换代码中的数据类型,得到了模板函数,实例化后的模板是真生的函数,可以被执行
125、什么是函数模板特例化
函数模板不适用某些特定类型的时候,可以使用特例化,必须跟函数模板一模一样
126、如何用栈实现队列
用两个栈实现队列,假设两个栈为是S1和S2
入队列:把数据加载进栈S1中
出队列,把栈S1中的数据全部压进S2中,然后依次弹出
127、局部变量能否和全局变量重名
能,局部会屏蔽全局。要用全局变量,需要使用 ":: "
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
128、Float x与“零值”比较的if语句
If(x>=0-0.00000001 && x<= 0+0.00000001)
129、引用与多态的关系
引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。
130、C++是不是类型安全的
类型安全的代码不会试图访问自己没被授权的内存区域。“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制;有的时候也用“类型安全”形容某个程序,判别的标准在于该程序是否隐含类型错误。
(1)操作符new返回的指针类型严格与对象匹配,而不是void*;
(2)C中很多以void*为参数的函数可以改写为C++模板函数,而模板是支持类型检查的;
(3)引入const关键字代替#define constants,它是有类型、有作用域的,而#define constants只是简单的文本替换;
(4)一些#define宏可被改写为inline函数,结合函数的重载,可在类型安全的前提下支持多种类型,当然改写为模板也能保证类型安全;
(5)C++提供了dynamic_cast关键字,使得转换过程更加安全,因为dynamic_cast比static_cast涉及更多具体的类型检查。
Main主函数执行完毕后,是否可能在执行一段代码,给出说明
Main退出之后,给调用exit函数,而exit函数里对依次调用atexit注册的函数,不过调用顺序是和atexit注册顺序相反的。
131、全局变量可不可以定义在可被多个.c文件包含的头文件中,为什么?
在不同的c文件中各自用static声明的全局变量,变量名尽管可能相同,但是各自c文件中的全局变量的作用域为该文件,所以互相不干扰
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
132、Static全局变量与普通全局变量有什么区别
两者都属于静态变量
区别在于:
1、普通全局变量的作用域在于整个源程序,而静态全局变量的作用域仅在定义该变量的源文件中有效,统一源程序的其他文件不能使用
2、普通全局变量在其他文件中也可使用,静态全局变量仅初始化一次,防止被其他文件单元引用
133、static函数与普通函数有什么区别?
1、static修饰的函数的作用与仅在本文件,其他文件不能访问,普通的函数可在其他文件中使用,把它加进头文件中就可以
2、Static函数在内存中只有一份,普通的函数在每个被调用中维持一份拷贝构造程序的局部变量存在于堆栈中,全局变量存在于静态区,动态申请数据存在于堆区
134、如何判断一段程序由c编译程序还是由C++编译程序编译的
1、如果编译器在编译cpp文件,那么cplusplus就会被定义,如果是一个c文件,那么_STDC_就会被定义,_STDC_是预定义宏,当它被定义之后,编译器就是按照ANSIC标准来编译c语言程序
#ifdef __cplusplus
cout<<”c++”;
#else
cout<<”c”;
#endif
2、另外如果在c++中采用C语言的编译方法,要加extern c
135、如何用C语言写死循环
While(1)
for(;1;)
Do {}while(1);
136、关键词volatile的作用
volatile的本意是“易变的”由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。
当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
优化器在用到这个变量时必须每次都小心地重新从内存里读取这个变量的值,而不是使用保存在寄存器里的备份。 遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
137、C++中的所有动作是不是都是由main()引起的,如果不是,请举例
比如说全局变量的初始化
全局的构造函数
138、C++中如何理解泛型
泛型主要是面向通用程序设计的,即一段逻辑代码可以被实例化为一系列不同的具体的实例,在c++中泛型主要是通过模板来支持的,例如STL(标准模板库)和Boost程序库
泛型可以作为一种程序的设计模式来理解
139、STL是什么
STL即Standard Template Library标准模板库,从根本上来讲,STL是一些容器的集合,这些容器有list、vector、set、map等,STL也是算法和其他一些部件的集合。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。
STL的最主要的两个特点:数据结构和算法的分离,非面向对象本质。访问对象是通过像指针一样的迭代器实现的;容器是像链表,矢量之类的数据结构,并按模板方式提供;算法是函数模板,用于操作容器中的数据。由于STL以模板为基础,所以能用于任何数据类型和结构。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组。
140、什么是智能指针
智能指针最基本的概念是引用计数,智能指针的内有有一个计数器,记录了当前有多少个指针在引用,当新增加一个可以访问这个资源的引用时,计数器就会加1,反之会减1,当计数器为0时,只能指针会自动释放他所管理的资源,手动申请,自动释放。
智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期。
在C++中,我们知道,如果使用普通指针来创建一个指向某个对象的指针,那么在使用完这个对象之后我们需要自己删除它,否则会造成内存泄露。在这个时候,智能指针的出现实际上就是为了可以方便的控制对象的生命期,在智能指针中,一个对象什么时候和在什么条件下要被析构或者是删除是受智能指针本身决定的,用户并不需要管理。
智能指针还有一个作用就是吧value语义转化为reference语义
141、什么是匿名函数
C++中的匿名函数,都是用Lambda表达式实现的,[]表示的是定义的lanbdo函数,中括号里也可以填入参数,()填写的lanbdo函数的参数列表,{}中就是函数体,编译器会自行判断函数的返回类型,也可以显示的只指定lambdo的返回类型。
如:[x](int n){return n<x};或者[](int n){count<<n};
142、如何定义JSON的数据格式
JSON是一种轻量级的数据交换格式,JSON完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。
JSON建构于两种结构:
1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
如:名称/值对{“firstname”:”Bret”}或者多个“名称/值对”的记录{ "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" }
2. 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
如:{ "people": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "bbbb"},
{ "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }
]}
在这个示例中,只有一个名为 people的变量,值是包含三个条目的数组,每个条目是一个人的记录,其中包含名、姓和电子邮件地址。
143、JSON和XML的区别
(1).可读性方面。
JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些。
(2).可扩展性方面。
XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
(3).编码难度方面。
XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
(4).解码难度方面。
XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
(5).流行度方面。
XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。
(6).解析手段方面。
JSON和XML同样拥有丰富的解析手段。
(7).数据体积方面。
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
(8).数据交互方面。
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。
(9).数据描述方面。
JSON对数据的描述性比XML较差。
(10).传输速度方面。
JSON的速度要远远快于XML。
JSON和XML的轻/重量级的区别在于:
JSON只提供整体解析方案,而这种方法只在解析较少的数据时才能起到良好的效果;
XML提供了对大规模数据的逐步解析方案,这种方案很适合于对大量数据的处理。
144、如何实现代码共享
宏函数、重载、函数模板