昨天,收到 SenseTime公司面试官的电话面试(一天面了三家公司,收获挺多的),通话时间将近1个半小时,面试过程中暴露出很多知识上的漏洞,本篇文章针对面试过程中继承以及虚函数方面的知识做一总结,查缺补漏,希望对大家有帮助。
单继承下的虚函数表
//单继承下虚函数表:是如何组织的 class A{ public: virtual void func(){ cout << "A::func" << endl; } virtual void funcA(){ cout << "A::funcA" << endl; } }; class B:public A{ public: virtual void func(){ cout << "B::func" << endl; } virtual void funcB(){ cout << "B::funcB" << endl; } }; class C:public A{ public: virtual void func(){ cout << "C::func" << endl; } virtual void funcC(){ cout << "C::funcC" << endl; } }; typedef void (*FUNC)(); int main() { A a; B b; C c; cout << "A::虚表:" << endl; ((FUNC)(*(int *)(*(int*)(&a))))(); ((FUNC)(*((int*)(*(int*)(&a)) + 1)))(); cout << "-------------------------------------" << endl; cout << "B::虚表:" << endl; ((FUNC)(*(int *)(*(int*)(&b))))(); ((FUNC)(*((int*)(*(int*)(&b)) + 1)))(); ((FUNC)(*((int*)(*(int*)(&b)) + 2)))(); cout << "-------------------------------------" << endl; cout << "C::虚表:" << endl; ((FUNC)(*(int *)(*(int*)(&c))))(); ((FUNC)(*((int*)(*(int*)(&c)) + 1)))(); ((FUNC)(*((int*)(*(int*)(&c)) + 2)))(); system("pause"); return 0; }
问题1:三个类中都有虚函数,所以三个类均有各自独立的虚函数表
问题2:三个虚函数表的组织情况,如上图所示
问题3:B、C各自拥有自己的虚函数表,互不影响
问题4:类的对象只存储指向虚函数表的指针vfptr(一般存储在对象内存布局的最前面),虚函数表只有一份,为所有对象所共享,vtable在Linux/Unix中存放在可执行文件的只读数据段中(rodata),而微软的编译器将虚函数表存放在常量段点击打开链接
typedef void(*FUNC)(); class A{ public: virtual void func(){ cout << "A::func" << endl; } virtual void funcA(){ cout << "A::funcA" << endl; } private: int a; }; class B{ public: virtual void func(){ cout << "B::func" << endl; } virtual void funcB(){ cout << "B::funcB" << endl; } private: int b; }; class C :public A, public B{ public: virtual void func(){ cout << "C::func" << endl; } virtual void funcC(){ cout << "C::funcC" << endl; } private: int c; };typedef void(*FUNC)(); class A{ public: virtual void func(){ cout << "A::func" << endl; } virtual void funcA(){ cout << "A::funcA" << endl; } private: int a; }; class B{ public: virtual void func(){ cout << "B::func" << endl; } virtual void funcB(){ cout << "B::funcB" << endl; } private: int b; }; class C :public A, public B{ public: virtual void func(){ cout << "C::func" << endl; } virtual void funcC(){ cout << "C::funcC" << endl; } private: int c; };
多继承条件下的虚函数表
//多继承条件下的虚函数表 void test() { C c; cout << "多继承条件下的虚函数表:" << endl; cout << "------------------------" << endl; ((FUNC)(*((int*)(*(int *)(&c)))))(); ((FUNC)(*((int*)(*(int*)(&c)) + 1)))(); ((FUNC)(*((int*)(*(int*)(&c)) + 2)))(); cout << "------------------------" << endl; ((FUNC)(*(int*)(*((int*)(&c) + 2))))(); ((FUNC)(*((int*)(*((int*)(&c) + 2)) + 1)))(); }
对象C的内存空间分布如下图所示:
多继承条件下,基类指针指向派生类后,基类指针所能访问的函数
//多继承条件下,基类指针指向派生类后,基类指针所能访问的函数 void test1() { C c; A *pa = &c; B *pb = &c; C *pc = &c; cout << "基类指针pa所能调用的函数:" << endl; pa->func(); pa->funcA(); //pa->funcB();error:提示类A没有成员funcB、funcC -->受到类型的限制 //pa->funcC();error cout << "基类指针pb所能调用的函数:" << endl; pb->func(); pb->funcB(); //pb->funcA();error //pb->funcC();error cout << "派生类指针pc所能调用的函数:" << endl; pc->func(); pc->funcA(); pc->funcB(); pc->funcC(); }
问题1:pa和pc的值相同,都是对象c的首地址,pb和pa至今相差四个字节(int a造成的-->观察上图的内存空间分配)
问题2:基类指针指向派生类的对象,通过该基类指针所能访问的函数受类型的限制(运行时调用哪个函数受多态的影响)
3:由于多态,会访问C类的func
4:通过加作用域:pa->A::func()
多继承条件下,基类指针指向派生类对象后,基类指针之间强制类型转化之后,所能访问的函数
void test2() { C c; A *pa = &c; B *pb = &c; C *pc = &c; pa = reinterpret_cast<A *>(pb); pa->func(); pa->funcA(); //pb = reinterpret_cast<B *>(pa); //pb->func(); //pb->funcB(); //pa = reinterpret_cast<A *>(pc); //pa->func(); //pa->funcA(); }
结果很奇怪(查看汇编分析)
最后一个简单地问题如下
相信你经过以上问题的分析,一定会回答出来(答案已经在图里面了^_^)