多态

一、多态
多态是指同样的消息被不同类型的对象接收时导致不同的行为。消息是指对类的成员函数的调用,不同的行为是指不同的实现,即调用了不同的函数。
二、多态的实现
从实现的角度可以划分两类:即编译时的多态和运行时的多态。
编译时的多态是在编译的过程中确定了同名操作的具体操作对象,运行时的多态则是在运行过程中才会动态的确定操作所针对的具体对象。这种确定操作的具体对象的过程称为绑定,指的是计算机程序自身彼此关联的过程,也就是把一个标识符名和一个存储地址联系在一起的过程。编译阶段完成的绑定称为静态绑定,也叫早绑定,运行阶段完成的绑定称为动态绑定,或者晚绑定。

二、多态性的举例

看看下面的代码:
class Shape
{
public:
    Shape(){}
    virtual void Draw(){}
    void fn1(){}
    virtual void fn2(){cout<<"Shape :: fn2"<<endl;}
    virtual void fn3(){cout<<"Shape :: fn3"<<endl;}
};
class Triangle:public Shape
{
public:
    Triangle(){}
    virtual void Draw(){cout<<"Triangle Draw"<<endl;}
    virtual void fn3(){cout<<"Triagnle : fn3"<<endl;}
    virtual void fn4(){cout<<"Triangle : fn4"<<endl;}
};
class Circle:public Shape
{
public:
    Circle(){}
    virtual void Draw(){cout<<"Circle Draw"<<endl;}
    virtual void fn2(){cout<<"Circle fn2"<<endl;}
    virtual void fn5(){cout<<"Circle fn5"<<endl;}
};
void test(Shape &a)    //引用形式
{
    a.Draw();
    a.fn2();
    a.fn3();
}
void test1(Shape *a)    //指针形式
{
    a->Draw();
    a->fn2();
    a->fn3();
}
void main()
{
    cout<<sizeof(Shape)<<endl;  //4
    Triangle t;    
    Circle c;   
    t.Draw();   //Triangle Draw
    c.Draw();   //Circle Draw
    cout<<endl;
    test(t);    //Triangle Draw  Shape::fn2   Triangle:fn3
    test(c);    //Circle Draw    Circle:fn2   Shape::fn3 
    cout<<endl<<endl;
    test1(&t);
    test1(&c);
}

如果一个类中有虚函数,则在本类中会增加一个VPTR,VPTR指向VTable,VTable中存放本类中虚函数的入口地址。下面给出我自己画的图来解释:(红色表明是子类对父类成员的造或者是新增的成员)
每个类都有一个虚表,在派生类的虚表中基类声明的函数对应的指针放在前面,派生类新增的虚函数的对应指针放在后面。每个多态类型的对象中都有一个指向当前类型的虚表的指针,该指针在构造函数中被赋值,通过基类的指针或引用调用一个虚函数时,就可以通过虚指针找到该对象的虚表,进而找到存放该函数的指针的虚表条目。将该条目中存放的指针读出后,就可获得应当被调用的函数的入口地址,然后调用该虚函数,这就是动态绑定的过程。
这里写图片描述

这里需要提到继承的步骤:全盘吸收,改造成员,最后添加新的成员。
所以Triangle类和Circle类先将父类完完整整的继承过来,然后在修改添加,最后的结果如上图所示。

运行结果:
这里写图片描述

执行一个类的构造函数时,首先被执行的是基类的构造函数,因此构造一个派生类的对象时,该对象的虚表指针首先会被指向基类的虚表。只有当基类构造函数执行完后,虚表指针才会被指向派生类的虚表,这就是基类构造函数调用虚函数时不用调用派生类构造函数的原因。

总结>实现多态要满足的条件:
1. 至少要含有两个类,且必须有父子关系
2. 实现多态的函数必须同名,同参,函数执行体可以不同
3. 基类中的同名同参函数必须有virtual关键字,子类可以不用写virtual
4. 必须是基类指针或引用指向基类指针或着是派生类指针或引用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值