简述C++虚函数作用及其底层实现原理
要点是要回答出虚函数表和虚函数表指针的作用。C++中虚函数使用虚函数表和虚函数指针实现,虚函数表是一个类的虚函数的地址表,用于索引类本身以及父类的虚函数的地址,假如子类的虚函数重写了父类的虚函数,则对应在虚函数表中会把对应的虚函数替换为子类的虚函数的地址;虚函数表指针存在于每个对象中(通常出于效率考虑,会放在对象的开始地址处),它指向对象所在类的虚函数表的地址;在多继承下,会存在多个虚函数表指针,分别指向对应不同基类的虚函数表。
一个对象访问普通成员函数和虚函数哪个更快
访问普通成员成员函数更快,因为普通成员函数地址在编译阶段就已经确定了,因此在访问时直接调用对应地址的函数。而虚函数在调用时,需要首先在虚函数表中寻找所在地址,因此相比普通成员函数速度要慢一些。
在什么情况下,析构函数需要时虚函数?
若存在类继承关系并且析构函数需要析构某些资源时,析构函数需要是虚函数,否则当使用父类指针指向子类对象时,在delete时只会调用父类的析构函数,而不能调用子类的析构函数,造成内存泄露等问题。
内联函数,构造函数和静态成员函数可以是虚函数吗?
都不可以,内联函数需要在编译阶段进行展开,而虚函数是在运行时动态绑定的,编译时无法展开;构造函数在进行调用时还不存在父类和子类的概念,父类只会调用父类的构造函数,子类调用子类的,因此不存在动态绑定的概念;静态成员函数是类的成员函数,不属于某个特定的对象,虚函数是与对象动态绑定的,因此是两个不冲突的概念。
补充:
构造函数和析构函数中的虚函数
构造派生类对象时,首先运行基类的构造函数初始化对象的基类部分。在执行基类构造函数时,对象的派生类部分是未初始化的。实际上此时的对象还不是一个派生类的对象。
撤销对象时,首先撤销它的派生类部分,然后按照与构造顺序逆顺序进行析构。
在这两种情况下,运行构造函数或析构函数时对象都是不完整的。为了适应这种不完整,编译器将对象类型视为在构造或者析构期间发生了变化。在基类构造函数或析构函数中,将派生类对象当做基类类型对象对待。
如果在构造函数或析构函数中调用虚函数,则运行的是构造函数或析构函数自身类型定义的版本。
extern C的作用
C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言不同。假设某个函数的原型为void foo(int x,int y).该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern C解决名字匹配问题。
评价一下C与C++的个子特点。如果一个程序即需要大量运算,又要一个好的用户界面;还需要和其他软件大量交流,应该怎样选择合适的语言
C是一种结构化的语言,重点在于算法和数据结构。C程序的设计首先考虑的是如何通过一个过程,对输入(或环境变量)进行运算得到输出。而对于C++,首先考虑的是构造一个对象模型,让这个对象模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程控制。
对于大规模数值运算,C/C++和java/.NET之间没有明显的性能特性。不过,如果涉及到向量计算和矩阵计算,可以使用matlab或者FORTRAN编写计算组件。
大规模用户界面相关软件可以考虑使用.NET进行开发(windows环境下),而且.NET同COM之间互操作十分容易,同时.NET对数据库访问的支持也相当好。