【c++知识归纳】继承与多态(二)
2016-08-26 04:50
513 查看
在继承与多态(一)中简单介绍了继承与多态的基础知识,本文将从内存中深入理解c++的继承与多态。
本文我选用了较低版本的IDE:【windows 10】系统的vs2008,因为高版本的处理比较复杂,为了看的更清楚,我们选择这个较低版本的编译器。
1.虚函数表(虚表)
调试上面的代码,打开监视和内存:
![](http://img.blog.csdn.net/20160825002724787?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
虚函数表:通过一块连续的内存来存储虚函数的地址。虚表指针指向这一块连续的空间。
2.单继承的对象模型
通过下面的代码来探索
同样,调试上面这段代码,打开内存和监视,来探索单继承子类对象在内存中的存储。
![](http://img.blog.csdn.net/20160826041251476?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
通过上面图片的分析,可以看到,当子类重写了父类的虚函数后,子类的函数地址直接将父类原来的函数地址覆盖,即虚表中的函数地址已经改为子类的函数地址了。所以当我们用父类的指针指向子类的对象时,调用的是子类重写的虚函数,这样就实现了多态。
3.多重继承的对象模型
![](http://img.blog.csdn.net/20160826044111922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
通过上图的分析,可以总结如下规律:
(1)有n个基类,则派生类就有n个虚表指针,也就有n个虚表。
(2)多重继承最左端的基类,它的虚表为主要表格,其中包含着Derive类的多有虚函数。
本文我选用了较低版本的IDE:【windows 10】系统的vs2008,因为高版本的处理比较复杂,为了看的更清楚,我们选择这个较低版本的编译器。
1.虚函数表(虚表)
class Base { public: Base() :_b(1) {} virtual void fun() { cout << "Base::fun()" << endl; } protected: int _b; };<pre class="cpp" name="code">int main() { Base b; system("pause"); return 0; }
调试上面的代码,打开监视和内存:
虚函数表:通过一块连续的内存来存储虚函数的地址。虚表指针指向这一块连续的空间。
2.单继承的对象模型
通过下面的代码来探索
class Base { public: Base() :_b(1) {} virtual void fun1() { cout << "Base::fun1()" << endl; } virtual void fun2() { cout << "Base::fun2()" << endl; } protected: int _b; }; class Derive:public Base { public: Derive() :_d(2) {} virtual void fun1() { cout << "Derive::fun1()" << endl; } virtual void fun3() { cout << "Derive::fun3()" << endl; } protected: int _d; }; typedef void(*pfun)(); void PrintVfptr(pfun *ppfun)//调用虚表中的函数 { for (int i = 0; ppfun[i] != NULL; i++) { ppfun[i](); } } void test() { Derive d; PrintVfptr((pfun*)(*(int *)&d)); } int main() { test(); system("pause"); return 0; }
同样,调试上面这段代码,打开内存和监视,来探索单继承子类对象在内存中的存储。
通过上面图片的分析,可以看到,当子类重写了父类的虚函数后,子类的函数地址直接将父类原来的函数地址覆盖,即虚表中的函数地址已经改为子类的函数地址了。所以当我们用父类的指针指向子类的对象时,调用的是子类重写的虚函数,这样就实现了多态。
3.多重继承的对象模型
class Base1 { public: Base1() :_b1(1) {} virtual void fun() { cout << "Base1::fun()" << endl; } virtual void fun1() { cout << "Base1::fun1()" << endl; } protected: int _b1; }; class Base2 { public: Base2() :_b2(2) {} virtual void fun() { cout << "Base2::fun()" << endl; } virtual void fun2() { cout << "Base2::fun2()" << endl; } protected: int _b2; }; class Derive :public Base1, public Base2 { public: Derive() :_d(3) {} virtual void fun() { cout << "Derive::fun()" << endl; } virtual void fun2() { cout << "Derive::fun1()" << endl; } virtual void fun3() { cout << "Derive::fun3()" << endl; } protected: int _d; }; typedef void(*pfun)(); void PrintVfptr(pfun* ppfun) { for (int i = 0; ppfun[i] != NULL; i++) { ppfun[i](); } } void test() { Derive d; printf("第1个虚表\n"); PrintVfptr((pfun*)(*(int*)&d)); printf("第2个虚表\n"); PrintVfptr((pfun*)(*((int*)&d+2))); } int main() { test(); system("pause"); return 0; }
通过上图的分析,可以总结如下规律:
(1)有n个基类,则派生类就有n个虚表指针,也就有n个虚表。
(2)多重继承最左端的基类,它的虚表为主要表格,其中包含着Derive类的多有虚函数。
相关文章推荐
- 【c++知识归纳】继承与多态(一)
- Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳
- c++面向对象三大特征封装、继承和多态知识总结
- C++ 类的相关知识 构造,析构,继承与多态
- Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳
- Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳
- C/C++一些知识4(重载与多态、虚继承)
- c++面向对象三大特征封装、继承和多态知识总结
- Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳
- Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳
- c++ 多态,继承的代价
- 搞清楚C++继承、多态、虚函数、纯虚函数
- 第05章 CORE C++_对象的创建和使用_继承_多态_析构_xxx_cast_友元_只读成员_静态成员_多重继承_虚继承_内部类
- 深入剖析C++继承,多态以及隐藏(二)。(纯虚函数以及重写与隐藏)
- c++中继承_多态
- MSN上关于C++多重继承和多态的聊天记录
- sogou interview ==> C 实现 C++ 封装 继承 多态
- 一段代码讲述C++继承、多态、友元、静态变量、重载
- 继承和多态和虚函数——C++学习笔记二
- C++标准中继承派生和多态知识补充