网易面经-基础知识

来源:互联网 发布:象棋网络直播 编辑:程序博客网 时间:2024/06/05 10:49

(1) 多态性都有哪些?

(静态和动态,然后分别叙述了一下虚函数和函数重载)
静态:函数重载;
动态:虚函数

(2) 动态绑定怎么实现?

(就是问了一下基类与派生类指针和引用的转换问题)
1. 为每一个包含虚函数的类设置一个虚表(VTABLE)每当创建一个包含有虚函数的类或从包含虚函数的类派生一个类时,编译器就会为这个类创建一个VTABLE。在VTABLE中,编译器放置了这个类中,或者它的基类中所有已经声明为 virtual 的函数的地址。如果在这个派生类中没有对基类中声明为 virtual 的函数进行重新定义,编译器就使用基类的这个虚函数的地址。而且所有VTABLE中虚函数地址的顺序是完全相同的。
2. 初始化虚指针(VPTR)然后编译器在这个类的各个对象中放置VPTR。VPTR在对象的相同的位置(通常都在对象的开头)。VPTR必须被初始化为指向相应的VTABLE。
3. 为虚函数调用插入代码 当通过基类的指针调用派生类的虚函数时,编译器将在调用处插入相应的代码,以实现通过VPTR找到VTABLE,并根据VTABLE中存储的正确的虚函数地址,访问到正确的函数。

虚函数调用过程:
1. 如果我们的程序是通过指向对象的指针或者是引用来调用该对象的虚函数,则在调用虚函数的过程需要查表(虚函数表)来调用真正的函数。
2. 调用的不是虚函数则不需要查表,在编译时即可确定调用的是那个函数。
3. 如果是通过对象来调用则对任何类型的函数都不需要查表。
4. 虚指针是在对象的构造函数中初始化的(所以构造函数不能是虚函数)。

对象在内存中的存在形式:

1.c++对象(基类对象)的内存布局是:对象的内存地址(&a)所指向的内存中的前四个字节中存放的是该对象的虚函数表的首地址(前提是该对象有虚函数),接下来的内存中依次存放该对象的数据成员(非静态的数据成员)。
虚函数的存放顺序与函数的顺序是相同的。

2.派生类的对象的内存布局是:前四个字节依然存放虚表指针,虚表中首先存放父类的虚函数地址,注意,由于派生类中也可能有①自己的虚函数,同时派生类也可以②重写父类的虚函数,虚函数表的分布如何:
对于情况一而言,将派生类新增加的虚函数地址依次添加到虚表(虚表中已经有父类的虚函数地址)的后面。
对于情况二而言,如果派生类重写了父类的虚,则将重写后的虚函数地址替换掉父类原来的虚函数地址,如果没有重写,则按照父类的虚表顺序存放虚函数地址

接下来的内存中依次存放该对象的父类的数据成员(非静态的数据成员),然后再存放派生类自己的数据成员。(还有内存对齐的问题)

(3) 类型转换有哪些?

(四种类型转换,分别举例说明)
1- const_cast,字面上理解就是去const属性。

const_cast是一种C++运算符,主要是用来去除复合类型中const和volatile属性(没有真正去除)。
变量本身的const属性是不能去除的,要想修改变量的值,一般是去除指针(或引用)的const属性,再进行间接修
http://bbs.csdn.net/topics/391915583?page=1

2- static_cast

与C语言强制转换不同的是,C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统都能转,而static_cast会进行类型检查,若俩不相干的类类型转换就不行。

3- dynamic_cast

命名上理解是动态类型转换。如子类和父类之间的多态类型转换。
dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
什么时候dynamic_cast是安全的?如果父类指针或引用指向的是一个子类对象时,这时将指针转换为子类指针是安全的
什么时候不安全?父类的指针或引用没有指向一个子类对象,而是指向一个父类对象的时候,这个指针转换为子类对象将是不安全的

4-reinterpreter_cast

仅仅重新解释类型,但没有进行二进制的转换。
不同类型的指针类型转换用reinterpreter_cast,最普通的用途就是在函数指针类型之间进行转换

(4) 操作符重载(+操作符),具体如何去定义,?

(让把操作符重载函数原型说一遍)(需要补充)

       函数类型 operator 运算符(形参表) {                 函数体; }

(5) 内存对齐的原则?(原则叙述了一下并举例说明)

   结构体也要对齐;

(6) 模版怎么实现?

(7) 指针和const的用法?

(就是四种情况说了一下)

指向const的指针(指针指向的内容不能被修改)const关健字总是出现在 * 的左边而const指针(指针本身不能被修改)const关健字总是出现在 * 的右边,那不用说两个const中间加个*肯定是指针本身和它指向的内容都是不能被改变的。

(8) 虚函数、纯虚函数、虚函数与析构函数?

(纯虚函数如何定义,为什么析构函数要定义成虚函数)
虚继承

解决钻石继承中,派生类中有多分祖类里的类成员(数据和方法)
在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。采用徐析构函数后,先释放派生类资源,再释放基类资源

(9) 内联函数

(讲了一下内联函数的优点以及和宏定义的区别)

  1. 内联函数在运行时可调试,而宏定义不可以;
  2. 编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会;
  3. 内联函数可以访问类的成员变量,宏定义则不能;
  4. 在类中声明同时定义的成员函数,自动转化为内联函数。
    优点是提高运行时间效率,减少函数进出栈;,缺点是增加了空间开销

(10) const和typedef

(主要讲了const的用处,有那些优点)
const类型的变量在声明的时候一定要进行初始化,否则会报错。

(11) 排序算法有哪些?快速排序怎么实现的?

最好时间复杂度,平均时间复杂度

(12) 链接指示:extern “C”(作用)

extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
http://www.jianshu.com/p/5d2eeeb93590
http://songpengfei.iteye.com/blog/1100239

(13) c语言和c++有什么区别?

(大体讲了 一下,继承、多态、封装、异常处理等

原创粉丝点击