萌蛋互动Visual C++面试经验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haimianjie2012/article/details/87428818

你是希望做前端还是后端?

没有直接回答,但是面试官似乎看出来了没有说实话,面露不悦之色。

你的职业规划是什么?

什么是多态?

虚函数的实现原理:

http://www.cnblogs.com/malecrab/p/5572730.html

线程Pa,pb,pc,有一个变量x=1,pa使用时命x=2;pb时命x=4;那么pc使用x,x的值是多少?

多线程资源共享

Class a,b;如何实现a=b报错?

Map的实现原理

Vector如何实现动态添加的

在 vector 对象构造期间,它先分配一个由其实现定义的默认的缓存大小。一般 vector 分配的数据存储初始空间是 64-256 存储槽slots)。当 vector 感觉存储空间不够时,它会自动重新分配更多的内存。

假设我们预先知道 ISBNs 的数量至少有 2000。那么就可以在对象构造期间指出容量,以便 vector 具有至少 2000 个元素的容量;除此之外,我们还可以调用 resize() 成员函数这样,便避免了中间的再分配,从而提高了效率。

一般首先定义一个空的vector对象,vector是用数组实现的,每次执行push_back操作,相当于底层的数组实现要重新分配大小(即先free掉原存储,后重新malloc);这种实现体现到vector实现就是每当push_back一个元素,都要重新分配一个大一个元素的存储,然后将原来的元素拷贝到新的存储,之后在拷贝push_back的元素,最后要析构原有的vector并释放原有的内存。

当添加元素时,如果vector空间大小不足,则会以原大小的两倍另外配置一块较大的新空间,然后将原空间内容拷贝过来,在新空间的内容末尾添加元素,并释放原空间。vector的空间动态增加大小,并不是在原空间之后的相邻地址增加新空间,因为vector的空间是线性连续分配的,不能保证原空间之后有可供配置的空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就会失效。

     start迭代器指向已用空间的首元素,finish指向已用空间的尾元素的下一个位置,end_of_storage指向可用空间的末尾。

     size()函数返回的是已用空间大小,capacity()返回的是总空间大小,capacity()-size()则是剩余的可用空间大小。当size()和capacity()相等,说明vector目前的空间已被用完,如果再添加新元素,则会引起vector空间的动态增长。

     由于动态增长会引起重新分配内存空间、拷贝原空间、释放原空间,这些过程会降低程序效率。因此,可以使用reserve(n)预先分配一块较大的指定大小的内存空间,这样当指定大小的内存空间未使用完时,是不会重新分配内存空间的,这样便提升了效率。只有当n>capacity()时,调用reserve(n)才会改变vector容量。

    resize()成员函数只改变元素的数目,不改变vector的容量。

Static主要应用场景,在程序中怎么存储的

用来控制变量的存储方式和可见性。

(1)静态局部变量

将一个函数中定义的变量声明为static对象,那么在函数被多次调用的过程中,静态局部对象会持续存在并保持它的值。

函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。

该变量在全局数据区分配内存;

静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;

静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;

它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

(2)类静态成员

static修饰类成员,使其成为类静态成员

static即可以修饰类成员变量,也可以修改类成员函数,是他们成为类静态成员。类静态成员是与类直接关联的对象,并不与该类的对象相关联。可以同归对象、指针和类来访问类静态成员。

需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。

可以节省内存,因为它是所有对象所公有的

(3)静态全局变量

在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量

该变量在全局数据区分配内存;

未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);

静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的; 

静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。

定义全局变量就可以实现变量在文件中的共享,静态全局变量不能被其它文件所用;

其它文件中可以定义相同名字的变量,不会发生冲突;

(3)静态函数

在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。静态函数不能被其它文件所用;
其它文件中可以定义相同名字的函数,不会发生冲突;

注意事项:

1.类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致

了它仅能访问类的静态数据和静态成员函数。

2.不能将静态成员函数定义为虚函数

静态函数,它其实就是普通函数。静态函数跟类实例没有关系,用a1和a2去调用结果一致,甚至于可以用A.fun2()的方式调用。静态函数调用时不会隐式传入this指针。

虚函数,是一种特殊的成员函数,用来实现运行时多态的

普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时邦定函数。

3.由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊

,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。

4.静态数据成员是静态存储的,所以必须对它进行初始化

程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中占据固定的存储单元

5. 初始化静态成员时不加该成员的访问权限控制符private,public等。

自己补充:静态成员函数访问非静态成员的方法

哪些函数不能声明为虚函数

为什么C++不支持普通函数为虚函数?

普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时邦定函数。

多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,普通

函数不属于成员函数,是不能被继承的。所以静态函数是不能定义为虚函数的。

为什么C++不支持友元函数为虚函数?

因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。友元函数不属于类的成员函数,不能被继承。

3.为什么C++不支持内联成员函数为虚函数?

inline函数和virtual函数有着本质的区别,inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够确定如何去调用的,因而inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。此外,一切virtual函数都不可能是inline函数。

调用webservice使用gosap协议,gosap协议使用tcp协议传输数据,说说tcp如何建立连接的

http://blog.csdn.net/u013898698/article/details/55511337

http协议get和post的区别

什么是HTTP?

超文本传输协议(HyperText Transfer Protocol -- HTTP)是一个设计来使客户端和服务器顺利进行通讯的协议。

HTTP在客户端和服务器之间以request-response protocol(请求-回复协议)工作。

GET - 从指定的服务器中获取数据

POST - 提交数据给指定的服务器处理

GET方法:

使用GET方法时,查询字符串(键值对)被附加在URL地址后面一起发送到服务器:

/test/demo_form.jsp?name1=value1&name2=value2

特点:

GET请求能够被缓存

GET请求会保存在浏览器的浏览记录中

以GET请求的URL能够保存为浏览器书签

GET请求有长度限制

GET请求主要用以获取数据

POST方法:

使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一起发送到服务器:

POST /test/demo_form.jsp HTTP/1.1

Host: w3schools.com

name1=value1&name2=value2

特点:

POST请求不能被缓存下来

POST请求不会保存在浏览器浏览记录中

以POST请求的URL无法保存为浏览器书签

POST请求没有长度限制

New创建的对象可以用free释放内存吗?

New|delete malloc|free必须成对使用,

Malloc|free是C++语言、C语言标准库函数,new|delete是C++库函数。

对于非内部基本数据类型来说,使用malloc|free无法满足要求,对象在创建的时候需要自动执行函数,在销毁是需要执行析构函数。Malloc|free是标准库函数,不在编译器控制权限之内,不能把构造函数和析构函数强加于malloc和free之上。

因此,C++语言需要一个完成动态分配内存和初始化工作的运算符new,以及一个能够完成内存清理和释放内存工作的运算符delete.

对于基本数据类型可能没有问题,但一旦涉及构造函数和析构函数就会出错,用free可能造成new出来的对象析构函数没有执行而导致程序出错。

Malloc和new的区别

不同点:

(1)操作对象有所不同。

malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符。对于非内部数据类的对象而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free。

因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。

new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。

(2)用法上也有所不同。

函数malloc 的原型如下:

void * malloc(size_t size);

用malloc 申请一块长度为length 的整数类型的内存,程序如下:

int *p = (int *) malloc(sizeof(int) * length);

我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。

1、malloc 返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。

2、 malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。

函数free 的原型如下:

void free( void * memblock );

为什么free 函数不象malloc 函数那样复杂呢?这是因为指针p 的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p 是NULL 指针,那么free

对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。

new/delete 的使用要点:

运算符new 使用起来要比函数malloc 简单得多,例如:

int *p1 = (int *)malloc(sizeof(int) * length);

int *p2 = new int[length];

这是因为new 内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型的对象而言,new 在创建动态对象的同时完成了初始化工作。如果对象有多个构造函数,那么new 的语句也可以有多种形式。

如果用new 创建对象数组,那么只能使用对象的无参数构造函数。例如

Obj *objects = new Obj[100];       // 创建100 个动态对象

不能写成

Obj *objects = new Obj[100](1);        // 创建100 个动态对象的同时赋初值1

在用delete 释放对象数组时,留意不要丢了符号‘[]’。例如

delete []objects; // 正确的用法

delete objects; // 错误的用法

后者相当于delete objects[0],漏掉了另外99 个对象。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        1、new自动计算需要分配的空间,而malloc需要手工计算字节数

        2、new是类型安全的,而malloc不是,比如:

                 int* p = new float[2]; // 编译时指出错误

                 int* p = malloc(2*sizeof(float)); // 编译时无法指出错误

          new operator 由两步构成,分别是 operator new 和 construct

        3、operator new对应于malloc,但operator new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上。而malloc无能为力

        4、new将调用constructor,而malloc不能;delete将调用destructor,而free不能。

        5、malloc/free要库文件支持,new/delete则不要。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

进程和线程的区别。

定义:

进程是具有一定独立功能的程序在某个数据集上运行的一次活动,是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分配的一个单位,它是比进程小的能够独立运行的独立单元,线程自己基本上不拥有系统资源,只拥有在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是他可以与其他属于同一进程的其他线程共享进程的全部资源。

关系:

一个线程可以创建或撤销另一个进程,同一个进程之间的多个线程可以并化执行。

相对于进程,线程更近似于执行体概念,它可以与同进程的其他线程共享数据,但是具有自己的栈空间,拥有独立的执行序列。

区别:

操作系统管理方式不同,进程具有独立的地址空间,一个进程崩溃后,在保护模式下不会影响到其他进程,而线程是同一进程的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有独立的地址空间,一个线程死掉等于一个进程死掉,所以多进程的程序比多线程的程序健壮。但是进程进行资源切换时,需要消耗很大,效率要低一些。同时要求并行和共享数据时,只能用线程。

总结:

一个程序至少有一个进程,一个进程至少有一个线程。

线程的划分尺度小于进程,使得多线程程序并发性高。

进程在执行时拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

执行过程有区别:每个线程拥有一个程序的入口,顺序执行序列,程序的出口,但线程不能独立执行,必须依存在应用程序中,由多线程提供程序执行控制。

从逻辑角度来看,线程的意义在于在一个应用程序中,多个执行部分可以同时执行。但操作系统并没有将多个线程看作独立的运用,来实现进程的调度和管理以及资源分配。

优缺点:

线程开销小,但不利于资源的管理和保护,进程相反;线程适合在SMP机器上运行,而进程可以跨机器运行。

猜你喜欢

转载自blog.csdn.net/haimianjie2012/article/details/87428818