C++中继承与多态的基础虚函数类详解
我们来使用这个函数,该函数代码如下: //单继承 class Base { public: virtual void func1() { cout << "Base::func1" << endl; } virtual void func2() { cout << "Base::func2" << endl; } private: int a; }; class Derive :public Base { public: virtual void func1() { cout << "Derive::func1" << endl; } virtual void func3() { cout << "Derive::func3" << endl; } virtual void func4() { cout << "Derive::func4" << endl; } private: int b; }; typedef void(*FUNC)(void); void PrintVTable(int* VTable) { cout<< " 虚表地址"<<VTable<< endl; for(inti = 0;VTable[i] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout<< endl; } int main() { Derive d1; PrintVTable((int*)(*(int*)(&d1))); //重点 system("pause"); return0; } 这里我就要讲讲这个传参了,注意这里的传参不好理解,应当细细的"品味". PrintVTable((int*)(*(int*)(&d1))); 首先我们肯定要拿到d1的首地址,把它强转成int*,让他读取到前4个字节的内容(也就是指向虚表的地址),再然后对那个地址解引用,我们已经拿到虚表的首地址的内容(虚表里面存储的第一个函数的地址)了,但是此时这个变量的类型解引用后是int,不能够传入函数,所以我们再对他进行一个int*的强制类型转换,这样我们就传入参数了,开始函数执行了,我们一切都是在可控的情况下使用强转,使用强转你必须要特别清楚的知道内存的分布结构。 最后我们来看看输出结果: 到底打印的对不对呢? 我们验证一下: 这里我们通过&d1的首地址找到虚表的地址,然后访问地址查看虚表的内容,验证我们自己写的这个函数是正确的。(这里VS还有一个bug,当你第一次打印虚表时程序可能会崩溃,不要担心你重新生成解决方案,再运行一次就可以了。因为当你第一次打印是你虚表最后一个地方可能没有放0,所以你就有可能停不下来然后崩溃。)我们可以看到d1的虚表并不是监视器里面打印的那个样子的,所以有时候VS也会有bug,不要太相信别人,还是自己靠得住。哈哈哈,臭美一下~ 我们来研究一下多继承的内存格局 探究完了单继承,我们来看看多继承,我们还是通过代码调试的方法来探究对象模型 看如下代码: class Base1 { public: virtual void func1() { cout << "Base1::func1" << endl; } virtual void func2() { cout << "Base1::func2" << endl; } private: int b1; }; class Base2 { public: virtual void func1() { cout << "Base2::func1" << endl; } virtual void func2() { cout << "Base2::func2" << endl; } private: int b2; }; class Derive : public Base1,public Base2 { public: virtual void func1() { cout << "Derive::func1" << endl; } virtual void func3() { cout << "Derive::func3" << endl; } private: int d1; }; typedef void(*FUNC) (); void PrintVTable(int* VTable) { cout << " 虚表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl; } void Test1() { Derive d1; //Base2虚函数表在对象Base1后面 int* VTable = (int*)(*(int*)&d1); PrintVTable(VTable); int* VTable2 = (int *)(*((int*)&d1 + sizeof (Base1) / 4)); PrintVTable(VTable2); } int main() { Test1(); system("pause"); return 0; } 现在我们现在知道会有两个虚函数表,分别是Base1和Base2的虚函数表,但是呢!我们的子类里的 (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |