c++学习总结(多态性)


在学习c++的过程中,根据自己的见解,把一些自己认为重要的、容易混淆的知识点记录下来,为了以后能够复习。今天主要总结多态性。主要从以下三个方面来讨论:what 、why 、how。

什么是多态性:

我们都知道多态性是为了实现接口的重用,我把它理解为"一个接口、多种方法",必须用virtual来实现多态。多态性作用于基类与子类之间,基类的函数定义为virtual函数,子类重写这个函数(此时子类的函数不需要显示指明为virtual).。

为什么使用多态:

对于这个问题,就要找多态性的优点了。多态能够实现接口的重用,也就是说命名了一个函数(函数名和参数都相同),但是函数体实现的功能各不相同,通过不同类的实例能够调用这个同名函数实现不同的功能,这也就实现了接口的重用。基类指针指向子类对象时,也能够调用子类的virtual函数,如果是调用子类的普通函数,那么还是实现基类自己的方法。

例子:

#include <iostream>
using namespace std;
/*定义一个基类*/
class Animal{
private:
char color; //颜色
int weight; //重量
public:
Animal(){}
void sleep()
{
cout<<"Animal want sleep"<<endl;
}
void virtual eat() // 虚函数
{
cout<<" Animal want eat meat"<<endl;
} 
};
class Dog : public Animal{
private:
char category;  //动物分类(家禽类...)
public:
Dog(){}
void sleep()
{
cout<<"Dog want sleep"<<endl;
}
void eat()
{ 
cout<<"Dog want eat meat"<<endl;
}
};
int main()
{
Dog dog;
Animal *p = &dog;
p->sleep();
p->eat();
}


这个例子的输出结果是:Animal want sleep

        Dog want eat meat

p->sleep() 调用的是Animal类的sleep方法,因为*p 虽然指向的是子类的对象,但是它本身是基类的实例,还是应该调用基类的方法。p->eat()调用的是子类的eat()方法,这里涉及到的是动态绑定。p->sleep()在预编译的时候就已经确定了调用哪个函数,即静态绑定;而p->eat() 是在执行的时候才确定具体调用哪个函数,即动态绑定。对于多态的问题,这时候在类中创建了虚函数表,里面存放类的虚函数的地址,另外还生成了个vptr指针,指向这个虚函数表。

下面看一下调用机制,首先类Animal分配了内存空间,存放成员变量和成员函数。其中成员函数由类的所有对象共享,而成员变量则是每个对象独有。由于类中有virtual函数,所以在编译的时候,内存上生成了一个虚函数入口地址,里面存放虚函数表,表里面有虚函数地址,这个入口地址占4个字节。派生类中也有个虚函数表,它是对基类虚函数表进行一次复制,如果子类重写了基类的virtual函数,那么子类的虚函数表中对应的位置存放的就是子类自己定义的虚函数的地址。(不然存放的依然是基类的虚函数地址,即没有对基类的虚函数进行重写时,基类对象调用的还是基类的虚函数)。机制:当执行p->eat() ;判断Animal类的eat()为虚函数,访问p所指向的对象dog,在对象中得到Dog的虚函数表,然后在基类声明中找到eat()的位序(在这里就要用到vptr指针),访问子类的虚函数表的位序,得到eat()的函数地址。请大家多多指正。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值