C++的多态性与虚函数

以下内容多来自《C++编程思想:第一卷》,现整理如下:

    C++通过虚函数实现了多态性。“多态性提供了接口与具体实现之间的另一层隔离,从而将"what"与"how"分离开来”--援引自《C++编程思想:第一卷》第一版p354。虚函数使得函数体与函数调用在运行时捆绑,即“晚捆绑”,从而实现了多态。

    C++如何实现多态的呢? 

“典型的编译器对每个包含虚函数的类创建一个表(称为VTABLE)。在VTABLE中,编译器放置特定类的虚函数的地址。在每个带有虚函数的类中,编译器秘密地放置一个指针,称为vpointer(缩写为VPTR),指向这个对象的VTABLE。当通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入能取得这个VPTR并在VTABLE表中查找函数地址的代码,这样就能调用正确的函数并引起晚捆绑的发生。”插入的这个指针可以通过以下例子看到:

// : Sizes.cpp
//  Object sizes with and without virtual functions

#include 
< iostream >
using   namespace  std;

#ifdef WIN32
    #include 
< windows.h >
#endif

class  NoVirtual  {
    
int a;
public:
    
void x() const {}
    
int i() const return 1; }
}
;

class  OneVirtual  {
    
int a;
public:
    
virtual void x() const {}
    
int i() const return 1; }
}
;

class  TwoVirtuals  {
    
int a;
public:
    
virtual void x() const {}
    
virtual int i() const return 1; }
}
;

int  main()  {
    cout 
<< "sizeof" << endl;
    cout 
<< "int : " << sizeof(int<< endl;
    cout 
<< "void* : " << sizeof(void*<< endl;
    cout 
<< "NoVirtual : " << sizeof(NoVirtual) << endl;
    cout 
<< "OneVirtual : " << sizeof(OneVirtual) << endl;
    cout 
<< "TwoVirtuals : " << sizeof(TwoVirtuals) << endl;

    #ifdef WIN32
        system(
"pause");
    
#endif

}
///:~

    继承含有虚函数的类时发生了什么?

“当实现继承和重新定义一些虚函数时,会发生什么事情?编译器对新类创建一个新VTABLE表,并且插入新函数的地址,对于没有重新定义的虚函数使用基类函数的地址。”举例来说,编译器能准确地把派生类Derived的VTABLE中的func1()的地址映射到和基类Base的VTABLE中同样的位置:

 ( 基类Base的VTABLE )                                ( 派生类Derived的VTABLE )
------------------------    <----------------->    --------------------------
|    & Base :: func1   |                                       |    & Base :: func1       |       ( 没有重写的虚函数 )
|    & Base :: func2   |                                        |    & Derived :: func2   |       ( 重写的虚函数 )
------------------------    <----------------->   |    & Derived :: func3   |       ( 新增的虚函数 )
                                                               
---------------------------

在派生类中增加新的虚函数时,若使用基类地址或指针调用新增的虚函数newFunc,会报错。这是因为根据基类地址无法确切地知道正在对那个类对象进行操作,这个地址可能指向一些没有新增函数newFunc的类。为了防止此类情况的发生,编译器会防止我们对只存在于派生类中的函数作虚函数调用。若真的需要调用这个新增的函数,则需要强制转换为派生类,再做调用。

    待续……

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值