C++之旅 虚函数

1、为什么了解决什么
     多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。C++中的多态性具体体现在运行和编译两个方面。运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。( 静态绑定和动态绑定
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
   C++中,实现多态有以下方法:虚函数,抽象类,覆盖,模板(重载和多态无关)。
   多态就是允许方法重名 参数或返回值可以是父类型传入或返回。 允许将子类类型的指针赋值给父类类型的指针。
   其实如果是这样的目的话,函数指针也可以实现多态。或我们反过来虚函数就是通过类名查找其 虚表指针 *__vptr ( void**)。
  

2、定义
     简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。它的 一般实现模型是:每一个类(class)有一个虚表(virtual table),内含该class之中有作用的虚(virtual)函数的地址,然后每个对象有一个vptr,指向虚表(virtual table)的所在。
    这个类大小就会多4个字节,这4个字节就是VTABLE的地址,这个类里的每个虚函数都是这个VTABLE数组的成员。

3、实现原理工作机制
     我们只要有虚函数的类,编译器都会为这个类创建一个VTABLE,用它来保存该类的所有虚函数地址。我们叫其函数指针数组。这个数组每个元素就是虚函数的地址。编译器给VTABLE置入了一指针VPTR。VPTR就是VTABLE的入口地址。 VPTR的值取决于对像内存的地址。
      每个类其VTABLE是独立唯一的,也就是说当构造该派生类实例(对象)时, 那么这个类会有一个virtual table,而每一个实例(对象)都会有一个virtual pointer(以下简称vptr)指向该类的virtual function tabl
  

4、例题: #include <iostream>
//www.realtoptv.com by zhangyj
//========================================================
//                 名字空间声明                                            
//========================================================
using std::cout;
using std::endl;
 
//Y = 0.30R + 0.59G + 0.11B , U = 0.493(B-Y), V = 0.877(R-Y)
 
//R = Y + 1.4075 *(V - 128)
//G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)
//B = Y + 1.779 *(U – 128)
//========================================================
 
//========================================================
class RGB2YUV
{
public:
 
    //默认构造函数
    RGB2YUV(int r = 1, int g = 1, int b = 1) :
        m_r(r), m_g(g), m_b(b)
    {
        cout << "RGB2YUV constructor called" << endl;
    }
 
    //定义为虚函数
    virtual int Y()
    {
        return  0.30*m_r + 0.59*m_g + 0.11*m_b;
    }
 
     virtual int U()
    {
        return  0.493*( m_b - Y() );
    }
 
     virtual  int V()
    {
        return 0.877*(m_r - Y());
    }
 
    //显示
       void ShowY()
    {
        cout << "Y volume is " << Y() << endl;
    }
    void ShowU()
    {
        cout << "U volume is " << U() << endl;
    }
    void ShowV()
    {
        cout << "V volume is " << V() << endl;
    }
protected:
    int m_r;
    int m_g;
    int m_b;
};
 
//========================================================
 
//========================================================
class PS_RGB2YUV : public RGB2YUV
{
public:
 
    PS_RGB2YUV(int r, int g, int b) :RGB2YUV(r, g, b){}
 
    //定义为虚函数
    virtual int Y()
    {
        return  0.30*m_r + 0.59*m_g + 0.11*m_b+1;
    }
 
    virtual int U()
    {
        return  0.493*(m_b - Y())+1;
    }
 
    virtual int V()
    {
        return 0.877*(m_r - Y())+1;
    }
};
 
 
//========================================================
//函数名   :main
//函数说明 虚函数的实现机制
//函数参数 :无
//返回值   :0
//========================================================
int main()
{
    RGB2YUV Wyuv(32, 32, 32);                    //基类对象定义   
    PS_RGB2YUV Wyuv_offset(32, 32, 32);    //派生类对象定义
 
    //显示
    Wyuv.ShowY();
    Wyuv.ShowU();
    Wyuv.ShowV();
 
    //显示派生类对象
    Wyuv_offset.ShowY();
    Wyuv_offset.ShowU();
    Wyuv_offset.ShowV();
 
    //显示类的大小
    cout << "Wyuv's size is " << sizeof(Wyuv) << endl;
    cout << "Wyuv_offset's size is " << sizeof(Wyuv_offset) << endl;
    system("pause");
}
   



8、反汇编分析
     //定义为虚函数
    29:     virtual int Y()
    30:     {
013C4AA0 55                   push        ebp  
013C4AA1 8B EC                mov         ebp,esp  
013C4AA3 81 EC CC 00 00 00    sub         esp,0CCh  
013C4AA9 53                   push        ebx  
013C4AAA 56                   push        esi  
013C4AAB 57                   push        edi  
013C4AAC 51                   push        ecx  
013C4AAD 8D BD 34 FF FF FF    lea         ediebp-0CCh]  
013C4AB3 B9 33 00 00 00       mov         ecx,33h  
013C4AB8 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
013C4ABD F3 AB                rep stos    dword ptr es:[edi]  
013C4ABF 59                   pop         ecx  
013C4AC0 89 4D F8             mov         dword ptr [this],ecx  
//每个实例都有this, 寄存器ECX里面的值作为this指针地址
    31:         return  0.30*m_r + 0.59*m_g + 0.11*m_b;
013C4AC3 8B 45 F8             mov         eax,dword ptr [this]  
013C4AC6 F2 0F 2A 40 04       cvtsi2sd    xmm0,dword ptr [eax+4]  
013C4ACB F2 0F 59 05 60 DC 3C 01 mulsd       xmm0,mmword ptr ds:[13CDC60h]  
013C4AD3 8B 4D F8             mov         ecx,dword ptr [this]  
013C4AD6 F2 0F 2A 49 08       cvtsi2sd    xmm1,dword ptr [ecx+8]  
013C4ADB F2 0F 59 0D C8 DC 3C 01 mulsd       xmm1,mmword ptr ds:[13CDCC8h]  
013C4AE3 F2 0F 58 C1          addsd       xmm0,xmm1  
013C4AE7 8B 55 F8             mov         edx,dword ptr [this]  
013C4AEA F2 0F 2A 4A 0C       cvtsi2sd    xmm1,dword ptr [edx+0Ch]  
013C4AEF F2 0F 59 0D B0 DB 3C 01 mulsd       xmm1,mmword ptr ds:[13CDBB0h]  
013C4AF7 F2 0F 58 C1          addsd       xmm0,xmm1  
013C4AFB F2 0F 2C C0          cvttsd2si   eax,xmm0  
    32:     }



virtual int Y()//调了2次值
    74:     {
013C4A30 55                   push        ebp  
013C4A31 8B EC                mov         ebp,esp  
013C4A33 81 EC CC 00 00 00    sub         esp,0CCh  
013C4A39 53                   push        ebx  
013C4A3A 56                   push        esi  
013C4A3B 57                   push        edi  
013C4A3C 51                   push        ecx  
013C4A3D 8D BD 34 FF FF FF    lea         edi,[ebp-0CCh]  
013C4A43 B9 33 00 00 00       mov         ecx,33h  
013C4A48 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
013C4A4D F3 AB                rep stos    dword ptr es:[edi]  
013C4A4F 59                   pop         ecx  
013C4A50 89 4D F8             mov         dword ptr [this],ecx  
//每个实例都有this, 寄存器ECX里面的值作为this指针地址
    75:         return  0.30*m_r + 0.59*m_g + 0.11*m_b+1;
013C4A53 8B 45 F8             mov         eax,dword ptr [this]  //调其实例
013C4A56 F2 0F 2A 40 04       cvtsi2sd    xmm0,dword ptr [eax+4]  
013C4A5B F2 0F 59 05 60 DC 3C 01 mulsd       xmm0,mmword ptr ds:[13CDC60h]  
013C4A63 8B 4D F8             mov         ecx,dword ptr [this]  
013C4A66 F2 0F 2A 49 08       cvtsi2sd    xmm1,dword ptr [ecx+8]  
013C4A6B F2 0F 59 0D C8 DC 3C 01 mulsd       xmm1,mmword ptr ds:[13CDCC8h]  
013C4A73 F2 0F 58 C1          addsd       xmm0,xmm1  
    75:         return  0.30*m_r + 0.59*m_g + 0.11*m_b+1;
013C4A77 8B 55 F8             mov         edx,dword ptr [this]    //调其实例
013C4A7A F2 0F 2A 4A 0C       cvtsi2sd    xmm1,dword ptr [edx+0Ch]  
013C4A7F F2 0F 59 0D B0 DB 3C 01 mulsd       xmm1,mmword ptr ds:[13CDBB0h]  
013C4A87 F2 0F 58 C1          addsd       xmm0,xmm1  
013C4A8B F2 0F 58 05 98 DD 3C 01 addsd       xmm0,mmword ptr ds:[13CDD98h]  
013C4A93 F2 0F 2C C0          cvttsd2si   eax,xmm0  
    76:     }  

9、总结
A、dynamic(late ) binding和static(early) binding 的实现优缺点
B、内存布局的优缺点
C、多重继承性的角度看优缺点
D、有多少种实现方法可以实现同样的功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值