首先我们看看多继承的多态是如何发生的。
#include <iostream>
using std::cout;
using std::endl;
class A
{
public:
virtual
void a()
{
cout<<"virtual A::a()"<<endl;
}
virtual
void b()
{
cout<<"virtual A::b()"<<endl;
}
virtual
void c()
{
cout<<"virtual A::c()"<<endl;
}
};
class B
{
public:
virtual
void a()
{
cout<<"virtual B::a()"<<endl;
}
virtual
void b()
{
cout<<"virtual B::b()"<<endl;
}
void c()
{
cout<<"B::c()"<<endl;
}
void d()
{
cout<<"B::d()"<<endl;
}
};
class C
:public A
,public B
{
public:
virtual
void a()
{
cout<<"virtual C::a()"<<endl;
}
void c()
{
cout<<"virtual C::c()"<<endl;
}
void d()
{
cout<<"C::d()"<<endl;
}
};
void test()
{
C c;
cout<<"&c = "<<&c<<endl;
//指向C中A的虚表
A* pa=&c;
cout<<"A*pa的地址pa = "<<pa<<endl;
pa->a();
pa->b();
pa->c();
cout<<endl;
//指向的虚表
B* pb =&c;
cout<<"B*pb的地址pb = "<<pb<<endl;
pb->a();
pb->b();
pb->c();
pb->d();
cout<<endl;
C* pc=&c;
cout<<"C*pc的地址pc = "<<pc<<endl;
pc->a();
//pc->b();//error
pc->A::b();
pc->B::b();
pc->c();
pc->d();
}
int main()
{
test();
return 0;
}
根据上述代码我们可以知道,我们用类C去继承类A和类B,其中基类A的成员函数abc均为虚函数,在类B中我们将ab设为虚函数,cd设为普通成员函数。这时我们让C去继承A和B。并分别用基类指针指向派生类对象会发生什么呢?
通过我们将pa,pb,pc指针的地址打印出来,我们可以知道派生类对象大概的内存布局。当发生多态时需要满足这些条件:
- 基类定义虚函数
- 派生类重写该虚函数
- 创建派生类对象
- 基类指针指向(基类引用绑定)派生类对象
- 使用基类指针或引用调用派生类虚函数
因此我们用基类指针指向派生类对象的时候,他指向的其实是派生类对象中虚表的地址。因此我们当用A *pa=&c;这时pa指向的就是从类A中继承并重写的虚函数表的指针vfptr。由于B* pb=&c;这时B中只有两个虚函数,由于C中没有b虚函数那他就会继承b的虚函数放入虚表;C中有a的虚函数就将B中的虚函数重写放入虚表,此时B中剩了两个普通成员函数,这时我们调用B类型的指针,如果指向虚函数他就会指向C虚表中的函数,非虚函数就会指向B中的普通成员函数。