多态+多态对象模型
来源:互联网 发布:mysql安装教程mac 编辑:程序博客网 时间:2024/06/04 19:50
多态的实现条件
多态(与对象有关 到对象的虚表中找到)=动态联编+虚函数重写
动态联编(运行时决议):指针/引用+虚函数
静态联编(编译时决议)与类型有关,像函数重载和通过对象名调用虚函数
1.定义一个父类的指针,如果这个指针指向父类,调用父类的虚函数,指针指向子类,调用子类的虚函数,这样可以使一个函数有不同的实现,即多态的体现。
2.根据模板的不同实例,实现不同类型的使用。
用一个例代码更好地理解
class A{public: virtual void f1() { cout<<"A::f1()"<<endl; } void f2() { cout<<"A::f2()"<<endl; } void f3() { cout<<"A::f3()"<<_a<<endl; }private: int _a;};int main(){ A* p = NULL; //p->f1();(运行不通过,此处动态联编,寻找虚表) p->f2();//静态联编,不是虚函数,f2存在于代码段中,直接可以调用 //p->f3();//(静态联编,this指针解引用后成空) return 0;}
虚析构函数
这里我们先来清楚一个问题,为什么最好把父类的析构函数定义成虚函数呢?
#include<iostream>using namespace std;class A{public: virtual~A() { cout<<"~A()"<<endl; }};class B:public A{public: ~B() { cout<<"~B()"<<endl; }};int main(){ A* p=new B; delete p; return 0;}
现象:给父类加上virtual后,会先析构子类的析构函数,再析构父类的析构函数。
分析:把父类的析构函数声明成虚函数,这将使所有派生类的析构函数自动成为虚函数。这样,如果想要显式地通过delete删除一个对象,delete的操作对象用了指向派生类对象的基类指针,则会调用基类的析构函数。
探索虚函数表
通过一块连续内存来存储虚函数的地址。
正如上图中监视显示,虚函数表_vfptr中存放着虚函数fun1和fun2的地址。
单继承有虚函数但是没有重写虚函数
通过监视窗口可以看到,父类中有一个虚函数,父类的实例化对象中有一个虚表指针和一个成员变量,然后子类中有一个函数,但不是虚函数,但为什么子类的成员变量里会有一个虚表指针呢?因为它是从父类里继承而来的。需要说明的是,这个函数指针,指向的内容是父类的虚函数。
单继承有虚函数有重写虚函数
class A{public: virtual void show() { cout<<"A show()"<<endl; }public: int _a;};class B:public A{public: void show() { cout<<"B show()"<<endl; } void show1() { cout<<"B show()"<<endl; }public: int _b;};int main(){ A a; B b; return 0;}
通过和上面的继承虚函数相比,子类的虚函数表中的函数地址已经变成了子类的函数了。
探索单继承对象模型
class Base{public: virtual void fun1() { cout<<"Base::fun1"<<endl; } virtual void fun2() { cout<<"Base::fun2"<<endl; }private: int a;};class Derive:public Base{public: virtual void fun1() { cout<<"Derive::fun1"<<endl; } virtual void fun3() { cout<<"Derive::fun3"<<endl; } virtual void fun4() { cout<<"Derive::fun4"<<endl; }private: int b;};void Test(){ Base b1; Derive d1;}
对于Derive类来说,我们预想的是,它的虚表里会有子类重写父类的fun1,父类的fun2,子类的fun3和fun4.
但是,通过监视窗口可知只有fun1()和fun2()。这里是因为编译器的问题所以没有显示出fun3和fun4。
所以接下来我们需要实现一个可以打印虚函数表的函数。
typedef void(*FUNC) ();void PrintVTable(int* VTable){ cout<<"虚表地址"<<VTable<<endl; for(int i=0;VTable[i]!=0;++i) { printf("低%d个虚函数地址:0X%x->",i,VTable[i]); FUNC f=(FUNC) VTable[i];//转为指针类型 f(); } cout<<endl;}void Test(){ Base b1; Derive d1; int* VTable1=(int*)(*(int*)&b1); int* VTable2=(int*)(*(int*)&d1); PrintVTable(VTable1); PrintVTable(VTable2);//显式打印}
函数的实现:
这里还有一点不好理解,就是传参问题
探索多继承的内存布局
学习了单继承对象模型,接下来我们看看多继承,同样,通过代码调试观察监视从而了解多继承的内存布局。
class Base1{public: virtual void fun1() { cout<<"Base::fun1"<<endl; } virtual void fun2() { cout<<"Base::fun2"<<endl; }private: int b1;};class Base2{public: virtual void fun1() { cout<<"Base::fun1"<<endl; } virtual void fun2() { cout<<"Base::fun2"<<endl; }private: int b2;};class Derive:public Base1,public Base2{public: virtual void fun1() { cout<<"Derive::fun1"<<endl; } virtual void fun3() { cout<<"Derive::fun3"<<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->",i,VTable[i]); FUNC f=(FUNC) VTable[i];//转为指针类型 f(); } cout<<endl;}void Test(){ Derive d1; int* VTable=(int*)(*(int*)&d1); PrintVTable(VTable); VTable = (int*)(*((int*)&d1+sizeof(Base1)/4)); PrintVTable(VTable);//显式打印}int main(){ Test(); return 0;}
多继承中有两个虚函数表,分别是Base1和Base2的虚函数表,我们猜想子类里的fun1()会覆盖父类Base1和Base2中的fun1(),但是子类里的fun3()会放在Base1里还是Base2里还是自己开辟一个虚函数表呢?
接下来,我们通过监视窗口看看:
结果证实了子类里的fun1()会覆盖父类Base1和Base2中的fun1(),但是,同单继承中出现的问题一样,编译器依旧无法在监视窗口中显示出fun3()的情况。
所以,靠自己吧!
通过上图的打印结果可知,fun3()存在于Base1的虚函数表中。当涉及多继承时,子类的虚函数会存放于先继承的那个类的虚函数表里。
- 多态&多态对象模型
- 多态&多态对象模型
- 多态&多态对象模型
- 多态&多态对象模型
- 多态&多态对象模型
- 多态&多态对象模型
- 多态&多态对象模型
- 多态+多态对象模型
- 多态+多态对象模型
- 多态&多态对象模型
- 多态+多态对象模型
- 多态对象模型
- 【c++】多态&多态对象模型
- 浅谈C++多态&多态对象模型
- C++ 多态&多态对象模型
- 多态&多态的对象模型
- 多态及其对象模型
- 多态的对象模型
- 深度理解“CPU内部寻址方式”
- jquery选取表单元素的方法
- 笨方法学Python习题 45: 对象、类、以及从属关系
- (1)helloworld:@Table、@Column、@Transient、@Temporal、@Enumerated
- SSH-CRUD-删除
- 多态+多态对象模型
- Python数据处理扩展包
- PL/SQ符号大全
- Solidity 字典映射Mappings
- 多线程的理解一
- Java for Web学习笔记(九二):消息和集群(7)RabbitMQ和消息模式(上)
- 数据结构实验之二叉树五:层序遍历
- IDEA搭建Spring+SpringMVC+mybatis框架教程
- 【tensorflow】CycleGAN + anaconda3 + tflearn + keras