程序员面试宝典三
2012-08-22 10:27 javaspring 阅读(207) 评论(0) 编辑 收藏 举报1、基类的析构函数声明为virtual的好处?
假设基类CBase,其派生类CChild,有如下代码:
CBase *pBase=new CChild; //new CChild构造对象时,先调用基类CBase的构造函数,然后调用CChild的构造函数,析构时顺序应该恰好相反。
delete pBase;
如果CBase的析构函数定义为virtual,那么pBase指针被撤销时,就会先调用CChild的析构函数,然后调用CBase的析构函数。
而如果CBase的析构函数不是virtual,那么只会调用CBase'的析构函数,从而导致内存泄漏。
2、构造函数为什么不可以声明为virtual型?
虚函数采用虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数。但是如果创造一个对象,你势必要知道对象的准确类型,因此构造函数不能为virtual型。
3、是否可以把类的每个函数(构造函数除外)声明为virtual型?
不行,因为虚函数是有代价的:由于每个虚函数的对象都必须维护一个v表,因此在使用虚函数的时候会产生一个系统开销。如果仅仅是很小的类,且不想派生其他的类,根本没有必要使用虚函数。
4、虚函数和虚继承
虚函数:类将维护一个虚函数表,来记录对应的函数入口地址
虚继承:派生类将维护一个虚类指针,来指向其父类。
5、虚函数的入口地址和普通函数区别?
每个虚函数在vtable中占了一个表项,该表项保存着虚函数的入口地址。当创建一个包含虚函数的对象时,该对象在头部附加一个指针,指向vtable中相应的位置。调用虚函数的时候,不管你是用什么指针调用的,它先跟据vtable找到入口地址再执行,从而实现了动态联编。而不像普通函数那样简单的跳转到一个固定的地址。
6、基类和派生类地址和布局,下面代码输出
#include "stdafx.h" #include <iostream.h> #include <string.h> class A { int a; }; class B { int b; }; class C:public A,public B //多重继承 { int c; }; void main() { C *c=new C; B *b=dynamic_cast<B*>(c); A *a=dynamic_cast<A*>(c); if (c==b) //两端数据类型不同,进行隐式转换,变成 c=(C*)b ; equal cout<<"equal"<<endl; else cout<<"not equal"<<endl; if (int(c)==int((C*)b)) //比较c和b隐士转换为(C*); equal cout<<"equal"<<endl; else cout<<"not equal"<<endl; if (int(c)==int(b)) //c和b的值不同,转换为int时也不相同; not equal cout<<"equal"<<endl; else cout<<"not equal"<<endl; }