您的位置:首页 > 其它

多态的实现原理

2016-08-20 19:11 417 查看

多态的实现原理是通过虚函数表和vptr指针实现的

多态的三个条件:1.继承,2.虚函数重写,3.父类指针或引用指向子类对象

class Parent
{
public:
virtual void func()
{
cout<<"parent::func()"<<endl;
}
virtual void func(int i)
{
cout<<"parent::func(int i)"<<endl;
}
};
class Child:public Parent
{
public:
virtual void func()
{
cout<<"Child::func()"<<endl;
}
virtual void func(int i)
{
cout<<"child::func(int i)"<<endl;
}
};


当类中声明虚函数时,编译器会在类中生成一个虚函数表;

虚函数表是一个存储类成员函数指针的数据结构;

虚函数表是由编译器自动生成与维护的;

virtual成员函数会被编译器放入虚函数表中;

存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr)

此时从上面的代码中就可以在编译器中生成下列表:

VTABLE:

void Parent::func()

void Parent::func(int)

void Child::func()

void Child::func(int)

所以:

Parent对象的VPTR指针指向了VTABLE中的Parent数据;

Child对象的VPTR指针指向了VTABLE表中的Child数据;

最后在调用时:

void run(Parent*p)
{
p->func();
}


此时编译器就会根据func是否为虚函数来进行相应的解释:

1.如果不是虚函数:编译器可直接确定被调用的成员函数(也叫做静态联编)

2.如果是虚函数:编译器根据对象p的VPTR指针所指向的虚函数表中来查找func函数并调用(也叫做动态联编或者迟邦定)

注意:通过虚函数表指针VPTR调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定真正应该调用的函数,而普通成员函数是在编译器时就确定了调用谁,因此虚函数的效率要低很多,所以不是虚函数越多越好。

下面来证明VPTR指针的存在。

class Parent1
{
public:
Parent1(int a=0)
{
this->a=a;
}
void print()
{
cout<<"我是爹"<<endl;
}
private:
int a;
};

class Parent2
{
public:
Parent2(int a=0)
{
this->a=a;
}
virtual void print()
{
cout<<"我也是爹"<<endl;
}
parent:
int a;
};
int main()
{
cout<<"sizeof(Parent1):"<<sizeof(Parent1)<<endl;
cout<<"sizeof(Parent2):"<<sizeof(Parent2)<<endl;
return 0;
}


第一个Parent1是没有虚函数,所以输出的是4

第二个Parent2是含有虚函数,所以输出的是4+sizeof(VPTR)=8;

因此只要定义了虚函数编译器就自动生成了VPTR指针。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多态实现原理