网易游戏开发面试题分享

时间:2021-09-09 16:17:08

原贴地址:http://www.zhihu.com/question/30034222

·●    inline关键字是做什么用的?inline关键字在什么情况下会展开失败?

      代码长度过大,会导致展开失败。inline类似于将代码直接替换,但是又不是。省去了调用函数的开销。增快了代码的执行效率。

  • sizeof一个空类是多大?为什么?编译器为什么这么做?
  • 1个字节,任何一个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址
  • 在这个类中添加一个virtual函数后再sizeof,这时是多大?为什么?
  • 4个字节,有virtual函数,就会对应一个指向虚函数表的vptr指针,指针的大小在32位系统中是4个字节.
  • 将这个类再virtual继承一个其它的空类,这是多大?为什么?
  • 12个字节,这个类本身大小为4个字节,空类的大小为1个字节,加上虚基类偏移量表指针4个指针,又因为要指针对齐(4个字节),故一起12个字节
  • 类有哪几种权限,分别说明?
  • private,protected,public
  • class A :class B{},A是私有继承还是? 私有继承是做什么用的?
  • 默认是私有继承,私有继承后,基类所有成员在派生类中为private成员。私有基类的public成员和protected成员在私有派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中称为不可访问的成员,只有基类的成员函数可以引用它们。
  • struct S{
  • char a;
  •    int b;
  •    static long c;
  • }
  • 请问sizeof(S)是多少?为什么,有什么好处?
  • 32位系统上,是8个字节,字节对齐,方便寻址操作。
  • 子类的虚函数中能不能调用父类的虚函数,为什么?
  • 有纯虚函数的类能不能实例化?
  • 不能,有纯虚函数的类是抽象类,只能被继承,不能实例化。包含纯虚函是的类派生出来的类都必须重写这个纯虚函数,举个例子,动物可以派生出狗,猫,牛等,动物本身是不可以被实例化的。
  • C++多态有哪几种?
  • 静态多态(函数重载和运算符重载),是在编译的时候,就确定调用函数的类型;动态多态(虚函数实现),在运行的时候,才能确定调用的是哪个函数,动态绑定。运行基类指针指向派生类的对象,并调用派生类的函数。
  • 应用形式上:静多态是发散式的,让相同的实现代码应用于不同的场合。动多态是收敛式的,让不同的实现代码应用于相同的场合。
  • 思维方式上:静多态是泛型式编程风格,它看重的是算法的普适性;动多态是对象式编程风格,它看重的是接口和实现的分离度。
  • C++是怎么实现动态多态的?
  • 虚函数表和指向虚函数表的vptr指针。这个需要注意vptr指针的分布初始化问题,是在构造函数之后,初始化列表和函数体之前完成的。
  • 对象中的VPTR指针什么时候被初始化?

    Vptr指针初始化的过程: 
    1.对象在创建的时,由编译器对VPTR指针进行初始化 
    2.只有当对象的构造完全结束后VPTR的指向才最终确定 
    3.父类对象的VPTR指向父类虚函数表 
    4.子类对象的VPTR指向子类虚函数表

    当定义一个子类对象的时候比较麻烦,因为构造子类对象的时候会首先调用父类的构造函数然后再调用子类的构造函数。当调用父类的构造函数的时候,此时会创建Vptr指针(也可以认为Vptr指针是属于父类的成员,所以在子类中重写虚函数的时候virtual关键字可以省略,因为编译器会识别父类有虚函数,然后就会生成Vptr指针变量),该指针会指向父类的虚函数表;然后再调用子类的构造函数,此时Vptr又被赋值指向子类的虚函数表。 
    (执行父类的构造函数的时候Vptr指针指向的是父类的虚函数表,所以只能执行父类的虚函数) 
    上面的过程是Vptr指针初始化的过程。 
    这是因为这个原因,在构造函数中调用虚函数不能实现多态。

  • 简要说说C++的静态多态?
  • 函数重载和运算符重载,见上上题。
  • C++编译后的函数符号和C语言编译后的函数符号有哪些区别?为什么
  • C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为void func(int x,int y)。该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。 C++中提供了C连接交换指定符号 extern "C" 解决名字匹配问题。
  • C++智能指针有哪些?auto_ptr和share_ptr有什么区别?他们有什么作用?
  • STL一共给我们提供了四种智能指针:auto_ptr,unique_ptr,shared_ptr和weak_ptr
  • auto_ptr的初衷是用来实现智能指针的,实现内存的自动回收。那么如何实现智能的呢?智能指针最基本的概念是引用计数,也就是智能指针内部有一个计数器,记录了当前内存资源到底有多少指针在引用(可以引用这个资源),当新增加一个可以访问这个资源的引用时,计数器会加1,反之会减去1,当计数器为0时,智能指针会自动释放它所管理的资源。手动申请,自动释放,就是智能的体现。RF:http://www.zhihu.com/question/20368881
  • 有序vector和list二分查找的时间复杂度分别是多少?
  • vector的二分相当于数组的二分,时间复杂度是O(logn),list没办法二分,只能每次从头到尾找,时间复杂度为O(n)。
  • vector自动扩容是按什么大小进行的?
  • 缺省的情况下vector的扩展机制是按2倍大小进行扩展的。在整个大小扩展的过程中,主要的步骤是:1.为需要的新容量分配足够的内存;2.将元素从原来的内存拷贝到新内存中去;3.销毁原来内存中的元素;4.归还原来的内存。
  • 图的搜索有哪几种方式?广搜要怎么做?需要什么额外空间吗
  • DFS和BFS,其中BFS需要开辟内存。
  • 给定一个迷宫,部分坐标是无法通过的,求某两点间最短路径?
  • 广搜+并查集
  • 简述Dijkstra算法的过程,描述一下A Star算法
  • 找出一个无序数组中大小后K个数据?
  • 类似于快速排序的思想,随机选取一个元素,把所有小于等于这个元素的数据移到左边,所有大于这个元素的数据移动到右边。
  • 如果这个元素成了第K个数,直接返回这个数。如果左边的个数大于K,不管右边的数了,在左边重复上面的过程。如果左边的个数等于T<K,不管左边的数了,重复上面的过程,只是K=K-T-1。平均情况下,第一次划分的时间复杂度是O(N),第二次就是O(N/2),总共是O(n+n/2+n/4+...)=O(n)
  • Set的底层实现是什么?红黑树是做什么用的?额外开销是多少?
  • set的底层实现是红黑树。红黑树是一种平衡二叉查找树。结点是红色或黑色。根节点是黑色,每个叶子结点都是黑色,每个红色结点的两个孩子结点都是黑色。从每个叶子到根的所有路径上不能有两个连续的红色结点。从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。
  • 红海色书和AVL树一样都对插入时间和删除时间以及查找时间提供了最好可能的最坏保障。时间复杂度是O(logn),需要额外的空间也是O(logn)
  • 程序有哪几种链接方式?分别说明区别?哪种效率高?如果一个动态库没有.lib和头文件,要怎么使用里面的函数?
  • 静态链接、装入时动态链接、运行时动态链接。
  • 1.静态链接:在程序运行之前,先将各个目标模块及它们所需的库函数,链接成一个完整的装配模块,以后不再拆开。我们把这种事先进行链接的方式称为静态链接方式。
  • 2.装入时动态链接:这是指将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的链接方式。
  • 3.运行时动态链接:这是指对某些目标模块的链接,是在程序执行中需要该目标模块时,才对它进行的链接。
  • 第三种方式效率较高。还可以节省大量的内存空间。
  • 线程和进程的区别?
  • 线程使用共享资源会出现什么问题?需要怎么做?
  • 如何进行线程同步?在Windows下举例?分用户模式下同步和内核模式下同步 讨论?
  • 用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。

    内核模式下的方法有:事件,信号量,互斥量。


  • 堆和栈的区别?
  • 线程死锁的几个条件是什么?
  • (1)互斥条件:指线程对所分配的资源进行排他性使用,即在一段时间内某资源只由一个线程占用。
  • (2)请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • (3)不可剥夺条件:进程已获得的资源,在未使用之前,不能强行剥夺。
  • (4)环路等待条件:指在发生死锁时,必然存在一个线程-资源的环形链,即线程集合{P0,P1,,P2,P3,...,Pn}中的P0正在等待P1占用的资源;P1正在等待P2占用的资源,...,Pn正在等待已被P0占用的资源。
  • 给定两个线程,A,B两个锁,举个造成死锁的例子?
  • 多个进程同时占有对方需要的资源而同时请求对方的资源,而它们在得到请求之前不会释放所占有的资源
  • TCP和UDP的区别?分别举例它们的上层协议?
  • TCP是基于连接的,可靠的,偏向于传输大量数据,速度慢,http,ftp,smtp,telnet使用了tcp;UDP是无连接的,不可靠的,偏向于传输少量数据,速度快,dns,tftp,rip,snmp,nfs等使用了udp。
  • 你用过哪些设计模式?
  • 工厂方法和抽象工厂有哪些区别?
  • 工厂方法模式属于对象创建型模式,它定义一个用户创建对象的接口,让子类决定实例化哪一个类。工厂方法模式使一个类的实例化延迟到其子类。具体来说就是一个一个抽象产品类,派生出很多个具体产品类;同时,一个抽象工厂类,派生出多个具体工厂类。而每个具体工厂类只能创建一个具体产品类的实例。
  • 抽象工厂模式也属于对象创建型模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无须制定它们具体的类。具体来说就是在多个抽象产品类中,每个抽象产品类可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类可以创建多个具体产品类的实例。
  • 区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
  • 工厂方法:说白了就是一个方法,这个方法是创建具体的产品的,它要求所有的工厂都具有同一个签名的方法,必要时重写该方法;
  • 抽象工厂:不能直接创建产品,只能创建工厂,即抽象工厂创建的产品是工厂。
  • 进程间通信有哪几种方式?在特定环境(比如两个程序需要共享一个文本)下哪种效率最高?Windows下如何进行内存共享?
  • 无名管道,有名管道,信号量,信号,高级管道,消息队列,共享内存,sokect等,共享内存的效率最高,因为它可以直接读写内存,而不需要任何的数据拷贝。windows下主要通过映射机制实现的。共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间中,这样每个进程都可以读取同一份数据,从而实现进程通信。因为是通过内存操作实现通信,因此是一种最搞笑的数据交换方法。
  • 给定1000亿个数据,要找出其中最大的一个值,内存只有1G?
  • 大文件变小文件,然后每个文件里hash_map统计最大的值,然后再归并排序。
  • 给定1000亿个数据,里边有的数据有重复,要求设计一个算法删除重复数据?要求尽量快。
  • 先取模分成小文件,然后每个文件使用hash_map或者trie树。