C++知识50问
1、C和C++的区别?C++相对于C的优势。
答:C是C++的基础,C++是C的超集。
C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理,得到输出(或实现过程控制).
C++ 首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程控制。
C++完美兼容C,所以C与C++最大的区别在于他们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“设计这个概念已经被融入到C++之中”。
简要概述C与C++的几点区别:
(1)全新的程序思维,C语言是面向过程的,C++是面向对象的。
(2)C语言有标准的函数库,他们松散的,只是把功能相同的函数放在一个头文件中;而C++对于大多数的函数都是有集成的很紧密。
(3)C++中的图形处理,他和C语言的图形有很大区别,C语言中的图形处理函数基本上是不能用在C++中的。C语言标准中不包括图形处理。
(4)C和C++中都有结构的概念,但是在C语言中结构只有成员变量,而没有成员方法,而在C++结构中,他可以有自己的成员变量和成员函数。
(5)C语言可以写很多方面的程序,但C++可以写的更多更好,C++可以写基于DOS的程序,写DLL,写控件,写系统。
(6)C语言对程序的文件组织是松散的,几乎是全要程序处理;而C++对文件的组织是以工程,个文件分类明确。
(7)C++可以自动生成你想要的程序结构,使你可以节省很多时间。有很多可用工具如加入MFC中的类的时候,加入变量的时候等等。
2、简述C的优缺点。
答:优点:(1)语言简洁、紧凑,使用方便、灵活。C语言关键字少,书写形式自由。
(2)丰富的运算符和数据类型。
(3)C语言可以直接访问内存地址,能进行位操作,使其能够胜任开发操作系统的工作。
(4)生成目标代码质量高,程序运行效率高。
(5)可移植性好。
缺陷:
(1)C类型检查机制相对较弱,这使得程序中的一些错误不能在编译时发现。
(2)C本身几乎没有支持代码重用的语言结构,因此一个程序员精心设计的程序,很难为其他程序所用。
(3)当程序的规模达到一定的程度时,程序员很难控制程序的发杂性。
3、在C++程序中,调用被C编译器编译后的函数,为什么要加extern “C”?
答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C的不同。C++提供了C连接交换指定符号:extern “C”来解决名字匹配问题。
4、C和C++中的struct有什么不同?
答:C和C++中的struct主要区别是C中的struct不可以含有成员函数,而C++中的struct可以;C++中的struct默认private,而C默认是public。
5、C++中struct和class的区别?
答:从语法上讲,class和struct做类型定义时只有两点区别:
(1)默认继承权限。如果不明确指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理。
(2)成员的默认访问权限。Class的成员默认是private权限,struct是public权限,除了这两点,class和struct基本就是一个东西,语法上没有任何其他区别。
6、C++函数中值的传递方式有哪几种?
答:值传递,指针传递,引用传递。
7、引用与指针的区别?为什么引用比指针安全?
答: 相同:都是地址的概念,指针指向一块内存,它的内容是所指向的内存的地址;引用是某块内存的别名。
不同:(1)指针是一个实体,而引用只是一个别名;
(2)引用使用时无需解引用,指针则需要;
(3)引用只能在定义时初始化一次,之后不可变;指针可变;
(4)引用没有const,指针有const;
(5)引用不能为空,指针可以为空;
(6)指针和引用的自增运算不一样;
(7)从内存分配上来看,程序为指针变量分配内存,而引用不需要分配内存区域。
(8)”sizeof(引用)”得到的是所指向的变量(对象)的大小,而”sezeof(指针)”得到的是指针本身的大小。
因为引用只在定义时被初始化一次,之后不可变;而指针的指向则是任意的。
8、面向对象的三个基本特征,并简单叙述之?
答:(1)封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected, public).
(2)继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法,而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。
(3)多态:是将父对象设置成为和一个或更多的与他的子类对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单地说,就是允许将子类类型的指针赋值给父类类型的指针。
9、C++中virtual与inline的含义分别是什么?
答:在基类成员函数的声明前加上virtual关键字,意味着将该成员函数声明为虚函数。Inline与函数的定义体放在一起,使该函数成为内联。Inline是一种用于实现的关键字,而不是用于声明的关键字。
虚函数的特点:如果希望派生类能够重新定义基类的方法,则在基类中将该方法定义为虚方法,这样可以启用动态联编。
内联函数的特点:使用内联函数的目的是为了提高函数的运行效率。内联函数体的代码不能过长,因为内联函数省去调用函数的时间,是以代码膨胀为代价的。内联函数不能包含循环语句,因为执行循环语句要比调用函数的开销大。
10、有了malloc/free为什么还要new/delete?
答:malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。他们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new和delete不是库函数。
11、如果在申请动态内存时找不到足够大的内存块,malloc和new将会返回NULL指针,宣告内存申请失败。你是怎么处理内存耗尽的?
答:(1)判断指针是否为NULL,如果是则马上用return语句终止本函数。
(2)判断指针是否为NULL,如果是则马上调用exit(1);终止整个程序的运行。
(3)为new和malloc设置异常处理函数。
12、C++是不是类型安全的?
答:不是,两个不同类型的指针之间可以强制类型转换。
13、多态类中的虚函数表时编译期间还是运行期间建立的?
答:在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组。而对象的隐藏成员--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键。
14、一个父类写了一个virtual函数,如果子类覆盖它的函数不加virtual,是否也能实现多态?
答:virtual修饰符会被隐形继承的。Virtual可加,可不加。子类的空间里有父类的所有变量(static除外)。同一个函数只存在一个实体(inline除外).子类覆盖它的函数不加virtual,也能实现多态。在子类的空间里,有父类的私有变量。私有变量不能直接访问。
15、多态的作用?
答:(1)隐藏实现细节,是的代码能够模块化;扩展代码模块,实现代码重用。
(2)接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。
16、内联函数在编译时是否做参数类型检查?
答:内联函数要做参数类型检查,这时内联函数跟宏相比的优势.
17、析构函数和虚函数的用法和作用?
答:析构函数是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只有在类对象的生命周期结束的时候,由系统自动调用。有释放内存的作用。虚函数是C++多态的一种表现,使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。
18、C++是有没有纯虚构造函数?
答:构造函数不能是虚的。只有虚的析构函数。
构造函数不能为虚函数,要构造一个对象,必须清楚地知道要构造什么,否则无法构造一个对象。
19、在C++的一个类中声明一个static成员变量有没有用?
答:在C++类的成员变量声明为static,意味着他为该类的所有实例所共享,也就是所当某个累的实例修改了该静态成员变量,不管创建多少对象,static修饰的变量只占有一块内存。其修改值为该类的其他所有实例所见;而类的静态成员函数也只能访问静态成员。Static是加了访问控制的全局变量,不被继承。
20、C++为什么用模板类?
答:(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全;
(4)它是平台无关的,可移植性;
(5)可用于基本数据类型。
21、函数模板与类模板有什么区别?
答:函数模板的实例化是由编译程序在处理调用时自动完成的,而模板的实例化必须由程序员在程序中显示的指定。
22、 介绍一下STL,详细说明STL如何实现vector?
答:STL,标准模板库,它由容器算法迭代器组成。
STL有以下的一些优点:
可以方便容易的实现搜索数据或对数据排序等一系列的算法;调试程序时更加安全和方便;即使是人们用STL在UNIX平台下写的代码你也可以很容易的理解。Vector实质上就是一个动态数组,会根据数据的增加,动态的增加数组空间。
23、在类中如何使用const?
答:有时我们希望某些常量只在类中有效。由于#define定义的宏常量是全局的,不能达到目的,于是想当然的觉得应该使用const修饰数据成员来实现。Const数据成员确实存在的,但其含义却不是我们所希望的。Const数据成员只是在某个对象生存周期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同,不能再类声明中初始化const成员只能在类构造函数的初始话列表中进行。
24、函数重载,我们靠什么来区分调用的是哪个函数?靠返回值判断可以不可以?
答:如果同名函数的参数不同(包括类型,顺序,个数不同),那么容易区分他们是不同的,如果同名函数仅仅是返回值类型不同,有时可以区分,有时却不能,因为在C/C++中我们可以忽略函数返回值。所以只能靠参数而不能靠返回值类型的不同来区分重载函数。
25、所有的运算符都能重载吗?举例说明
答:在C++运算符集合中,有一些运算符是不允许被重载的,这种限制是出于安全方面的考虑,可以防止出错和混乱。
(1)不能改变C++内部数据类型(如int, float等)的运算符。
(2)不能重载 ’.’ ,因为 ’.’ 在类中对任何成员都有意义,已经成为标准用法。
(3)不能重载目前C++运算符集合中没有的符号,如#,@等等,原因有二:一是难以理解;二是难以确定优先级。
(4)对已经存在的运算符进行重载时,不能改变优先级规则,否则将引起混乱。
26、基类的析构函数不是虚函数会带来什么问题?
答:派生类的析构函数用不上,会造成资源的泄露。
27、C++的空类,默认产生哪些成员函数?
答:缺省构造函数,拷贝构造函数,虚构函数,赋值运算符,取址运算符,取址运算符const。
28、拷贝构造函数中,深拷贝和浅拷贝,临时对象?
答:深拷贝意味着拷贝了资源和指针,而浅拷贝只是拷贝了指针,没有拷贝资源,这样使得两个指针指向同一份资源,造成对同一份资源析构两次,程序崩溃。临时对象的开销比局部对象小些。
29、C++中哪些函数不能被声明为虚函数?
答:普通函数(非成员函数),构造函数,内联成员函数,静态成员函数,友元函数。
(1)虚函数用于基类和派生类,普通函数所以不能。
(2)构造不能是因为虚函数采用的是虚调用的方法,允许在只知道部分信息的情况的工作机制,特别允许调用只知道接口而不知道对象的准确类型的方法,但是调用构造即使要创建一个对象,势必要知道对象的准确类型。
(3)内联成员函数的实质是在调用的地方直接将代码扩展开。
(4)继承时,静态成员函数是不能被继承的,他只属于一个类,因为也不存在动态联编等
(5)友元函数不是类的成员函数,因此也不能被继承。
30、对于一个频繁使用的短小的函数,C中用什么实现,C++中用什么实现?
答:C中使用宏定义;C++使用inline
31、多继承情况下,构造函数的执行顺序。
答:构造函数按下列顺序被调用:
(1)任何虚拟基类的构造函数按照他们被继承的顺序构造。
(2)任何非虚拟基类的构造函数按照他们被继承的顺序构造。
(3)任何成员对象的构造函数按照它们声明的顺序调用。
(4)类自己的构造函数。
32、继承的访问权限中private和protected的区别?
答:在单个类中,private和protected没有什么区别;但在继承关系中,基类的private成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,热而对派生类则毫不隐瞒。
33、赋值兼容规则中所指的替代包括哪些情况?
答:(1)派生类的对象可以赋值给基类对象。
(2)派生类的对象可以初始化基类的引用。
(3)派生类对象的地址可以赋给指向基类的指针。
34、什么是继承和派生?继承的方式有哪些?有什么区别?
答:继承:在保持已有类的特性的基础上,构造新类的过程。
派生:在已有类的基础上新增自己的特性而产生新类的过程。
派生继承,虚拟继承,多重继承。
方式 public protected private
1,Public public protected private
2,Protected protected protected private
3,Private private private private
35、虚函数的作用?
答:可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类指针调用其虚函数,则会调用其真正指向对象的成员函数,而不是基类中定义的成员函数。若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都会调用基类中定义的那个函数。(即虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数)。
36、命名空间的作用?
答:(1)规定该文件中使用的标准库函数都是在命名空间中定义的。
(2)为了避免变量或者函数重命名的问题。
37、重载和重写的区别?
答:重载:允许存在多个同名函数,而这些函数的参数表不同。
重写:用于继承,子类重新定义父类虚函数的方法。
从实现原理上:
重载:编译器根据函数不同的参数表,对同名函数的名词作修饰,然后这些同名函数就成了不同的函数。重载和多态无关。
重复:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的,因此这样的函数地址是在运行期绑定的。
38、重载在C++中的作用?
答:重载的意义在于他可以用相同的名字访问一组相互关联的函数,由编译程序来进行选择,因而这将有助于解决程序复杂性问题。如在定义类时,构造函数重载给初始话带来了多种形式,为用户提供更大的灵活性。
39、宏与内联函数的区别?
答:内联函数和宏的区别在于,宏是由预处理器对红进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到时,内联函数像宏一样展开,所以取消了函数的参数压栈,减少了调用的开销。
40、Main函数执行前,还会执行什么代码?
答:全局对象的构造函数会在main函数之前执行。
41、STL中各类容器及使用场合?
42、一般数据库若是出现日志满了或数据库满了,会出现什么情况,是否还能继续使用?
答:只能执行查询等读操作,不能执行更改,备份等写写操作,原因是任何写操作都要记录日志。也就是说基本上处于不能使用的状态。
43、SQL Server是否支持行级锁,有什么好处?
答:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据的一致性和准确性,行级锁确保在用户取得被更新的行到该行进行更新这段时间内不被其他用户所修改、因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。
44、将引用作为参数有哪些特点?
答:(1)传递引用给函数与传递指针的效果是一样的。这时函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此当参数传递的数据较大时,引用比一般变量传递参数的效率个所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使引用相同的效果,但在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
45、类的静态成员和非静态成员有何区别?
答:类的静态成员每个类只有一个,静态成员为所有的类的实例对象所共享,静态成员有静态成员变量个静态成员函数,静态成员变量使用前必须初始化,静态成员变量可以被静态成员函数和非静态成员函数访问,而静态成员函数只能访问静态成员变量,因为静态成员函数属于类,其没有this指针,非静态成员每个对象都有一个。
46、什么是封装?C++中是如何实现的?
答:封装来源于信息隐藏的设计理念,是通过特性和行为的组合来创建新数据类型让接口与具体实现相隔离。C++中是通过类来实现的,为了尽量避免某个模块的行为干扰同一系列系统中的其他模块,应该让模块仅仅公开必须让外界知道的接口。
47、什么是拷贝构造函数?
答:它是单个参数的构造函数,其参数是与它同属一类的对象的引用;类定义中,如果未提供自己的拷贝构造函数,C++提供一个默认拷贝构造函数,该默认拷贝构造函数完成一个成员到一个成员的拷贝。
48、面向对象程序设计的优点?
答:开发时间短,效率高,可靠性高。面向对象编程的编码具有很高的可重用性,可以在应用程序中大量采用成熟的类库,从而缩短了开发时间,软件易于实现维护和升级。
49、C++中内存的分配方式?
答:(1)从静态存储区分配
内存在编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快,不易出错,因为有系统善后。
(2)在栈上分配:
在执行函数是,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配
即动态内存分配。程序在运行的时候用malloc或new申请的任意大小的的内存,程序员自己负责何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活。但频繁的分配和释放不同大小的堆空间将会产生堆内碎块。
50、MySQL中varchar和char的区别?
答:char是一种固定长度的类型,varchar则是一种可变长度的类型。Varchar比char更灵活,且不占内存空间。但varchar的速度却比char慢。对于大多数情形,使用varchar会更好。
51、带参宏与带参函数的的区别?、
答:(1)函数调用时,先求出实参表达式的值,然后带人形参。而是用带参宏只是进行简单的字符替换。
(2)函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开是在编译时进行的,在展开时不进行内存分配,不进行值的传递处理,没有返回值的概念。
(3)对函数中的形参和实参都要定义类型,类型要求一致,如不一致则进行类型转换。而宏不存在类型问题
(4)调用函数只可得到一个返回值,而用宏则可以设法得到几个结果。
(5)使用宏次数多时,宏展开后源程序边长,每展开一次源程序增长,函数调用则不会。
(6)宏替换不占用运行时间,只占编译时间,而函数调用占用时间。
52、