多态+多态对象模型

来源:互联网 发布:中国能源研究会 知乎 编辑:程序博客网 时间:2024/06/05 02:26

一:什么是多态。

面向对象语言有三大特点,封装----继承----多态。

今天就讨论一下多态,多态是当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,当指向子类就是调用子类的虚函数。

多态:多种形态。 多态分为静态多态和动态多态。(实现多态的其中一个条件必须是要把子类给给父类,要构成is-a的关系)

注意:必须是基类的指针或引用调用。不能是父类的对象(因为传对象时,只是临时拷贝,只能拿到成员数据,拿不到成员函数,而传引用或指针就什么都拿到)。

二:多态的对象模型--单继承&多继承

单继承:

#include <iostream>
using namespace std;
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 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 Test1 ()
{
Base b1 ;
Derive d1 ;
int* VTable1 = (int*)(*( int*)&b1 );
int* VTable2 = (int*)(*( int*)&d1 );
PrintVTable(VTable1 );
PrintVTable(VTable2 );
}
int main()
{
Test1();
return 0;
}

剖析:

首先通过监视窗口分析

其次通过内存来看:   

多继承:

#include <iostream>
using namespace std;
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,->", i , VTable[i ]);
FUNC f = (FUNC) VTable[i ];
f();
}
cout<<endl ;
}
void main ()
{
Derive d1 ;
int* VTable = (int*)(*( int*)&d1 );
PrintVTable(VTable );
// Base2虚函数表在对象Base1后面
VTable = (int *)(*((int*)&d1 + sizeof (Base1)/4));
PrintVTable(VTable );
}

可以通过监视窗口与内存分析得知:

                    所以多继承的时候,子类的虚函数放在了先继承的基类的虚表中

三:多态的对象模型--菱形继承和菱形虚拟继承

#include <iostream>
using namespace std;
class Base
{
public:


virtual void fun1()
{
cout<<"void fun1"<<endl;
}
virtual void fun2()
{
cout<<"void fun2"<<endl;
}
int _a;
};
class Base1:public Base
{
public:
virtual void fun1()
{
cout<<"void fun1"<<endl;
}
virtual void fun3()
{
cout<<"void fun3"<<endl;
}
int _b;
};
class Base2:public Base
{
public:


virtual void fun1()
{
cout<<"void fun1"<<endl;
}
virtual void fun14()
{
cout<<"void fun4"<<endl;
}
int _c;
};
class Derive:public Base1,public Base2
{
public:
virtual void fun1()
{
cout<<"void fun1"<<endl;
}
virtual void fun5()
{
cout<<"void fun5"<<endl;
}
int _d;
};
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 ;
}


int main()
{
Base a;
Base1 a1;
Base2 a2;
Derive d1;
int* VTable1 = (int*)(*( int*)&a );
int* VTable2 = (int*)(*( int*)&a1);
int* VTable3 = (int*)(*( int*)&a2);
int* VTable4 = (int*)(*( int*)&d1);
PrintVTable(VTable1 );
PrintVTable(VTable2 );
PrintVTable(VTable3 );
PrintVTable(VTable4 );


return 0;
}

菱形继承成员变量时需要虚继承不然会造成二义性:程序无法跑过编译

所以此时就需要菱形虚拟继承才能结果问题:

代码与源代码相同只是稍微在两个Base类前加一个virtual


分析:菱形虚拟继承

分开来看 先看子类的函数:函数部分与上面一种情况的函数分布相同:


原创粉丝点击