目录
-
- 1、C++为什么要提出引用?(引用和指针的区别?)
- 2、使用const而不是#define来定义常量?
- 3、C++左值和右值的区别?
- 4、全局变量?
- 5、static关键字?
- 6、C++和C的区别?
- 7、智能指针(smart pointer)?
- 8、堆和栈?
- 9、程序的内存模型分为那几个区域?
- 10、malloc/free和new/delete的区别?
- 11、那你知道如果用free去清理new出来的内存会产生什么问题吗?
- 12、vector实现?
- 13、迭代器失效了解吗?
- 14、std::sort原理?
- 15、深拷贝和浅拷贝?
- 16、为什么list不能使标准库算法sort()?
- 17、解决哈希冲突的方法有哪些?
- 18、容器适配器?
- 19、STL(标准模板库或泛型库,内容太多,这里只是简述)?
- 20、C++哪些容器不支持迭代器?
- 21、函数名后加const?
- 22、静态成员函数为什么不能访问本类中的非静态成员?
- 23、为什么静态成员函数不能声明为const?
- 24、内存对齐?
- 25、大端存储、小端存储?
- 26、虚析构函数?
- 27、构造函数可以是虚函数吗?不可以
- 以下几个问题问法不一样,其实问的都是多态的东西
- 28、静态联编和动态联编?(重载overloaded和重写、覆盖的区别?)
- 29、C++静态多态和动态多态?
- 30、C++多态,关于虚函数、虚函数表、虚指针、重写与覆盖?
- 31、C++多继承?
- 32、菱形继承与虚继承?
- 33、让C++程序变得更高效更安全的一些技巧?
- 34、一个程序从源代码到可执行程序的过程?
- 35、链接?
- 36、类中的 public, protect, private?
- 37、struct和class区别?
- 38、用类的空指针调用成员函数?
1、C++为什么要提出引用?(引用和指针的区别?)
引用变量在功能上等于一个常量指针(到底是常量指针还是指针常量?有的书上写的常量指针,有的博客里写的指针常量,那就不纠结这个问题吧。总之这里指的是顶层const),即一旦指向某一个单元就不能在指向别处。
(1)我们在用指针的使用经常犯的错误是什么?
①操作野指针;
②不知不觉改变了指针的值,而后还以为该指针正常。
如果我们要正确的使用指针,我们不得不人为地保证这两个条件。而引用的提出就是解决这个问题。
引用区别于指针的特性是:
① 必须初始化(保证不是野指针);
② 一个引用永远指向他初始化的那个对象(保证指针值不变)。
所以引用的提出就是:让人为地保证这两个条件变成让编译器保证。这样可以减少错误的产生。
(2)程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
(3)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
2、使用const而不是#define来定义常量?
- ①const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而后者仅仅进行字符替换,没有类型安全检查,并且在字符替换过程中会产生一些意料不到的错误。
- ②const方法可以很方便地用于复合类型。
如const int a[3]={1,2,3}; - ③const标识符遵循变量的作用域原则,可以创建作用域为全局、名称空间、数据块的常量。
3、C++左值和右值的区别?
- 左值:lvalue(locator value)代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。
- 右值:rvalue通过排他性来定义,每个表达式不是lvalue就是rvalue。因此从上面的lvalue的定义,rvalue是在不在内存中占有确定位置的表达式。
4、全局变量?
特点:
- ① 作用域:全局可见。
全局变量(外部变量)是在函数外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾。
注:通常把超出一个函数的作用域称为全局作用域,其他几种(如块作用域)不超出一个函数的作用域称为局部作用域。 - ② 存储空间:静态存储区
系统会在执行时将全局变量分配在静态存储区,在程序执行期间,对应的存储空间不会释放,一直到程序结束才会释放。
注:一个程序在内存中占用的存储空间可以分为3个部分:程序区(存放可执行程序的代码)、静态存储区(存放静态变量)、动态存储区(存放动态变量)。 - ③ 优先度:全局变量优先度低于局部变量
当全局变量和局部变量重名时,会屏蔽全局变量,局部优先。
优点:使用全局变量程序运行时速度会快一点,因为内存不需要再分配。
缺点:使用全局变量会占用更多的内存,因为其生命期长。
全局变量作用域的扩展和限制:
-
① 扩展:使用extern关键字可以对全局变量的作用域进行扩展。
前面提到,全局变量的作用域为从变量的定义处开始,到本程序文件的末尾。若想在本文件全局变量定义之前引用该全局变量,可以在引用之前用extern关键字对该变量进行说明,有了此说明,就可以从说明之处起,合法地引用该变量。
若想在一个文件(设为a.cpp)中引用另一个文件(设为b.cpp)中已定义的全局变量,可以在a.cpp中extern关键字对该全局变量进行说明,在编译和连接时,系统就会知道该全局变量已经在其他文件(b.cpp)中定义过了。
注:在编译时遇到extern,系统会现在本文件中查找全局变量的定义,如果找到,就在本文件中扩展作用域;如果找不到,就在连接时在其他文件中查找全局变量的定义,如果找到,就将作用域扩展到本文件;如果还找不到,按出错处理。 -
② 限制:使用static关键字可以限制全局变量的作用域。(又称之为隐藏)
全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern对全局变量进行声明,就可以使用全局变量。
如果希望全局变量仅限本文件引用,而不能被其他文件引用,可以在定义全局变量时在前面加一个static关键字。
全局变量和全局静态变量的区别:
首先,并不是说全局变量在定义时加了static关键字才是静态存储,不加static就是动态存储,不是的。不管加不加static,全局变量都是存储在静态存储区的,都是在编译时分配存储空间的,两者只是作用域不同,全局变量默认具有外部链接性,作用域是整个工程,全局静态变量的作用域仅限本文件,不能在其他文件中引用。
5、static关键字?
特点:用来控制存储方式和可见性
- ① 存储空间:静态存储区(控制变量的存储方式)
静态变量存储在静态存储区(存储在静态存储区的变量,如果不显式地对其进行初始化,系统会将其初始化为0),在程序执行期间,对应的存储空间不会释放,一直到程序结束才会释放。
static控制变量的存储方式体现在局部变量上。局部变量存储在动态存储区,在局部变量定义前加上static,该局部变量就变成了局部静态变量,局部静态变量存储在静态存储区,即使函数调用结束,它占用的存储空间也不会释放,但其他函数不能引用该局部静态变量。当下一次调用该函数时,不会再次对该局部静态变量进行初始化,它的值是上一次函数调用结束时的值。
对全局变量而言,存储方式没有什么改变,因为全局变量和全局静态变量都存储在静态存储区。 - ② 作用域:(控制变量、函数的可见性)
static控制变量的可见性体现在全局静态变量和静态函数上。
全局变量默认具有外部链接性,作用域是整个工程。使用static关键字可以限制全局变量的作用域,全局静态变量的作用域仅限本文件,它对在其他文件不可见,也就是说不能在其他文件中引用该全局静态变量,但其他文件中可以定义和它名字相同的变量,不会发生冲突。
在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数的不同在于,它只能在声明它的文件当中可见,不能被其它文件使用,其它文件中可以定义相同名字的函数,不会发生冲突。
局部静态变量的作用域与局部变量的作用域相同,其作用域都是从定义开始到函数或程序块结束为止。
类中的static关键字:
在类中声明static变量或者函数时,初始化时使用作用域运算符(::)来标明它所属类,静态成员是类的成员(所有对象中共享的成员),而不是某一个对象的成员。
-
① 静态数据成员
在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。
静态数据成员和普通数据成员一样遵从public,protected,private访问规则。
对于非静态数据成员,每个对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只会被分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新。
因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它。
同全局变量相比,使用静态数据成员有两个优势:
静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能; -
② 静态成员函数
与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的,如函数fun()实际上是this->fun()。但是与普通函数相比,静态成员函数由于不与任何的对象相联系,因此它不具有this指针。
非静态成员函数可以任意地访问静态成员函数和静态数据成员;
静态成员函数不能访问非静态成员函数和非静态数据成员;静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
什么时候用static?
需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
为什么要引入static?
函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题:如果想将函数中此变量的值保存至下一次调用时,如何实现?最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。
6、C++和C的区别?
设计思想上:
C++是面向对象的语言,而C是面向过程的结构化编程语言,C++在C的基础上增加了类。
语法上:
① C++具有封装、继承和多态三种特性。
② C++相比C,增加了许多类型安全的功能,比如强制类型转换。
③ C++支持范式编程,比如模板类、函数模板等。
④ 在C++中,引用是一个经常使用的概念。引用型变量是其他变量的一个别名,我们可以认为他们只是名字不相同,其他都是相同的。
⑤ 在C++语言中,仍然支持malloc()和free()来分配和释放内存,同时增加了new和delete来管理内存。
⑥ C++支持函数重载,允许有相同的函数名,不过它们的参数类型不能完全相同,这样这些函数就可以相互区别开来。而这在C语言中是不允许的。
7、智能指针(smart pointer)?
智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。
C++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr,其中后三个是c++11支持,并且第一个已经被11弃用。
为什么要使用智能指针?
动态内存的使用中很容易出现问题。比如,申请的空间忘记释放,造成内存泄漏;或者在后面还会使用到该指针的情况下释放了内存,在这种情况下就引用了非法内存的指针。
用智能指针可以很大程度上的避免这些问题,因为智能指针就是一个类(而且还是像vector这样的模板类,当我们创建一个智能指针时,还必须提供额外的信息——指针可以指向的类型),当超出了类的作用域是,类会自动调用析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
shared_ptr:
shared_ptr允许多个指针指向同一个对象。当指向某一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象,它是通过析构函数来完成销毁工作的。
weak_ptr:
weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造而来。weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能