多继承与虚函数

来源:互联网 发布:数据备份自动还原 编辑:程序博客网 时间:2024/06/12 02:57

本章结论:

1、多继承时派生类只能通过其直接继承的基类的指针指向它(下面中的B类,C类)。

2、一个类的指针只能调用该类中定义过或者继承下来的函数

正文

1、B继承A,C继承A,D继承B,C(A中有虚函数)

此时,不能用A的指针指向D类对象,因为A类指针不知道该指向B前面还是C前面。


class A{public:virtual void a() { cout << "A::a()" << endl;}private:int da = 1;};class B : public A{public:virtual void a() { cout << "B::a()" << endl;}virtual void b() { cout << "B::b()" << endl;}private:int db = 2;};class C : public A{public:virtual void a() { cout << "C::a()" << endl;}virtual void c() { cout << "C::c()" << endl;}private:int dc = 3;};class D : public B, public C{public:virtual void d() { cout << "D::d()" << endl;}private:int dd = 4;};

当主函数如下时

int main(){B* objptr = new D;int* iptr = (int*)objptr;int* vtptr1 = (int*)(iptr[0]);cout << iptr[0] << endl << iptr[1] << endl << iptr[2] << endl << iptr[3] << endl << iptr[4] << endl << iptr[5] << endl << iptr[6] << endl;return 0;}
输出

当主函数如下时

int main(){C* objptr = new D;int* iptr = (int*)objptr;int* vtptr1 = (int*)(iptr[0]);cout << iptr[0] << endl << iptr[1] << endl << iptr[2] << endl << iptr[3] << endl << iptr[4] << endl << iptr[5] << endl << iptr[6] << endl;return 0;}
输出

从上面的输出可以看出,当用B类指针指向D类对象时,指针指向的是D中B数据块的首地址;当用C类指针指向D类对象时,指针指向的是D中C数据块的首地址;

接下来我们来研究下D的虚函数表

主函数如下

int main(){B* objptr = new D;int* iptr = (int*)objptr;int* vtptr_b = (int*)(iptr[0]);((void (*)())(vtptr_b[0]))();((void (*)())(vtptr_b[1]))();((void (*)())(vtptr_b[2]))();return 0;}
输出

主函数如下时

int main(){C* objptr = new D;int* iptr = (int*)objptr;int* vtptr_c = (int*)(iptr[0]);((void (*)())(vtptr_c[0]))();((void (*)())(vtptr_c[1]))();((void (*)())(vtptr_c[2]))();return 0;}
输出

根据以上的实验,我们可以推断出,D有两个虚表



如果D重写函数a(),那么D的虚表就会变成如下(已通过程序验证):


至于为什么不是上图中的右边那样,因为

当C* ptrc = new D()时,ptrc是一个C类指针,那么ptrc至少可以调用C中定义过的a()和c()两个函数,至于最后多态效果是谁的不重要。所以,vtptr_c指向的虚表一定至少要有两个函数指针。

0 0
原创粉丝点击