您的位置:首页 > 其它

8月8 某公司一面

2017-08-08 12:07 120 查看
1、C++程序设计考虑的问题

答:面向对象的三个特征:封装、继承、多态。封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

单一职责原则(Single-Resposibility Principle):对一个类而言,应该仅有一个引起它变化的原因。高内聚低耦合

开放封闭原则(Open-Closed principle):软件实体应该是可以扩展的,但是不可修改。不修改源代码,可扩招功能,在C++中,这各抽象是指抽象基类或纯抽象基类

Liskov替换原则(Liskov-Substituion Principle):子类型必须能够替换掉它们的基类型

依赖倒置原则(Dependecy-Inversion Principle):先抽象后具体,从笼统到细节

接口隔离原则(Interface-Segregation Principle):多个专用接口优于一个单一的通用接口,一个接口应该保证实现该接口的实例对象可以只呈现为单一的角色

良性依赖原则:不会在实际中造成危害的依赖关系,都是良性依赖
2、有哪些情况导致内存泄漏

答:总的来说就是内存没有释放,程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费

在类的构造函数和析构函数中没有匹配的调用new和delete函数

释放对象数组的时候delete没有用[]:数组中存放的是对象,只需要delete []p,即可调用对象数组中的每个对象的析构函数释放空间
缺少拷贝构造函数:在C++中,如果没有定义拷贝构造函数,那么编译器就会调用默认的拷贝构造函数,会逐个成员拷贝的方式来复制数据成员,如果是以逐个成员拷贝的方式来复制指针被定义为将一个变量的地址赋给另一个变量。这种隐式的指针复制结果就是两个对象拥有指向同一个动态分配的内存空间的指针。当释放第一个对象的时候,它的析构函数就会释放与该对象有关的动态分配的内存空间。而释放第二个对象的时候,它的析构函数会释放相同的内存,这样是错误的。所以,如果一个类里面有指针成员变量,要么必须显示的写拷贝构造函数和重载赋值运算符,要么禁用拷贝构造函数和重载赋值运算符(浅拷贝深拷贝)
缺少重载赋值运算符,没有将基类析构函数设置为虚函数
野指针

3、指针和引用的区别

答:指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。从概念上讲,指针是存放变量地址的一个变量,在逻辑上是独立的,可以被改变;引用是一个别名,逻辑上不独立,具有依附性,所以必须在一开始就被初始化。值传递时,指针形参是实参的一个副本,不影响主调函数的是参变量值,而引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。

●指针是一个实体,而引用仅是个别名;

●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

●引用没有const,指针有const,const的指针不可变;

●引用不能为空,指针可以为空;

●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

●指针和引用的自增(++)运算意义不一样;

●引用是类型安全的,而指针不是 ,引用比指针多了类型检查

4、进程的几种状态以及如何转化

答:


     三种状态:就绪态、运行态、阻塞态  就绪态是在等待cpu的资源,阻塞态是在等在cpu以外的资源

1)就绪——运行:对就绪状态的进程,当进程调度程序按一种选定的策略从中选中一个就绪进程,为之分配了处理机后,该进程便由就绪状态变为执行状态;
2)执行——阻塞:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为阻塞状态,如进程提出输入/输出请求而变成等待外部设备传输信息的状态,进程申请资源(主存空间或外部设备)得不到满足时变成等待资源状态,进程运行中出现了故障(程序出错或主存储器读写错等)变成等待干预状态等等; 
3)阻塞——就绪:处于阻塞状态的进程,在其等待的事件已经发生,如输入/输出完成,资源得到满足或错误处理完毕时,处于等待状态的进程并不马上转入执行状态,而是先转入就绪状态,然后再由系统进程调度程序在适当的时候将该进程转为执行状态;
4)执行——就绪:正在执行的进程,因时间片用完而被暂停执行,或在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行而被迫让出处理机时,该进程便由执行状态转变为就绪状态。

5、进程中常用的通信方式

答:最常用的是:信号、信号量、消息队列、共享内存

 # 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。    因此,主要作为进程间以及同一进程内不同线程之间的同步手段

# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区   大小受限等缺点。

# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能
ba09
在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

6、const什么情况下用,解释一下extern c

答:常类型的变量和对象的值是不能被更新的,因此定义的时候就要初始化。在c++程序中,它还可以修饰函数的定义体,定义类中某个成员为常态函数,即不改变类中的数据成员。被const修改的东西都要受到强制保护,可以预防意外的变动,能提高程序的健壮性。(常变量、常对象、常成员函数/成员变量、常引用和指针)

 const与#define相比有什么不同?它们都可以用来定义常量,但const比#define有更多优点:
(1) const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。(2) 在c++中使用const常量而不使用宏常量,即const常量完全取代宏常量。
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。extern "C",会指示编译器这部分代码按c语言的规则进行编译

7、空类的大小,加了虚函数之后的大小

答:sizeof空类的大小为1,因为声明一个类型的实例时,必须在内存占有一定的空间,否则无法使用这些实例。加虚函数之后,就会为该类型添加一个虚函数表,在实例中添加指向虚函数表的指针。在32位机器中sizeof为4,64位机器中为8

8、虚函数机制,动态绑定原理

无数次问了。。。

9、tcp三次握手、四次挥手。四次挥手中,time wait的时间是多少

答:四次挥手中,被动关闭方给主动关闭方响应一个ack之后进入close_wait状态,继续传输自己没传完的数据。主动关闭方收到fin,发送ack之后进入time_wait,等待2MSL(最大报文生存时间),然后关闭socket

10、算法:一个int数组,里面的数有正有负,找到它的一个连续子序列,让它的和最大。时间复杂度是多少

答:动态规划问题,每一个数据看它前面的数据子序列是正是负。正数的话,把自己添加到那个子序列中,负数的话子序列从自己重新开始。这样。每个数据所在的那个序列就是和最大的子序列。

别人的百度一面:

1、如何判断两个链表是否相交,能否只遍历一遍

答:方案一:蛮力法。从head1开始,逐个与head2中的每个结点的地址比较,看是否相等。注意为了避免存在相同的元素,我们采取比较地址的方法,而不是比较元素,在判断链表里是否有环的时候,也是采用比较地址的方法。时间复杂度为O(N*N)。

方案二:利用空间换时间的做法。采用计数法。如果两个链表相交则说明该链表有相同的结点。而地址有时其唯一的标示,所以我们还是可以采取和方案一一样的比较地址的方案。只不过我们使用哈希表,将链表head1每个结点的地址进行hash取值,然后遍历haed2链表一遍,我们就可以得出是否有相同的结点,也就是是否存在相交。这里是时间复杂度为:O(N)=O(Lenght(head1)+Length(head2))+辅助空间O(Lenght(head1))。

方案三:判断最后一个节点是否相同,所以我们可以通过两次遍历,得到两个链表的最后一个结点,然后通过比较这两个链表的地址是否相同来判断它们是否相交。时间复杂度:O(Lenght(head1)+Length(head2))=O(N)。

方案四:由于链表里没有环。那么我们可以将该问题进行转化,将head1头结点接到head2的尾部,这样我们就可以通过判断head2链表里有没有环来进行判断,他们是否相交。判断有没有环,设置快慢指针。

2、两个素数,中间夹了一个数,证明这个数能被6整除

3、TCP  3次握手详细过程

4、TCP 拥塞控制方法

5、C++智能指针的底层实现,对象是在引用计数减为0后立即析构吗?

6、讲一下虚函数

7、为什么构造函数不能是虚函数?

答:1、构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的.而在构造一个对象时,由于对象还未构造成功.编译器无法知道对象的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类.无法确定.

2、虚函数对应一个vtable,可是这个vtable在构造函数中进行初始化工作,其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。

8、讲一下设计模式中的抽象工厂模式

9、LINUX下如何查看磁盘利用率、CPU负载、一个指定进程的启动目录、如何修改用户对文件的权限、如何将一个用户从一个用户组转到另一个用户组

答:使用top命令

10、用过vim的哪些命令,如何在vim中查找一个C++函数的定义位置

11、讲一下读写锁和互斥锁,以及他们的用法;互斥锁是如何实现的?

12、了不了解一致性哈希?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: