首页 > 其他 > 详细

Virtual Function

时间:2015-03-24 09:16:26      阅读:161      评论:0      收藏:0      [点我收藏+]

虚函数,直接上个代码吧,这份代码很长,因为其中研究了一下虚函数的实现,虽说好像什么也没懂。

#include <iostream>
#include <stdio.h>
using namespace std;

class Base {
  
  public:
    Base() {}
    virtual ~Base() {}
    void non_virtual_show() {
        cout << "it shows I am a Base(non_virtual)" << endl;
    }
    virtual void virtual_show() {
        cout << "it shows I am a Base(virtual)" << endl;
    }
    virtual void virtual_show_1() {}
    virtual void virtual_show_2() {
        cout << "successfully call virtual_show_2 in base" << endl;
    }
};

class Derive_1 : public Base {
    
  public:
    void non_virtual_show() {
        cout << "it shows I am a Derive_1(non_virtual)" << endl;
    }
    virtual void virtual_show() {
        cout << "it shows I am a Derive_1(virtual)" << endl;
    }
    virtual void virtual_show_1() {}
    virtual void virtual_show_2() {
        cout << "successfully call virtual_show_2 in derive_1" << endl;
    }
};

int main() {
    
    //PART 1 without pointer
    Base b1;
    Derive_1 d1;
    b1.non_virtual_show();
    b1.virtual_show();
    d1.non_virtual_show();
    d1.virtual_show();
    cout << endl;
    
    //PART 2 with pointer
    Base *p1 = new Base;
    Base *p2 = new Derive_1;
    Derive_1 *p3 = new Derive_1;
    //Derive_1 *p4 = new Base; invalid conversion
    p1->non_virtual_show();
    p1->virtual_show();
    p2->non_virtual_show();
    p2->virtual_show();
    cout << endl;
    
    //PART 3 address
    void (Base::*B_pointer)();
    B_pointer = &Base::non_virtual_show;
    printf("%p\n", B_pointer);
    B_pointer = &Base::virtual_show;
    printf("%p\n", B_pointer);
    B_pointer = &Base::virtual_show_1;
    printf("%p\n", B_pointer);
    B_pointer = &Base::virtual_show_2;
    printf("%p\n", B_pointer);
    cout << endl;
    
    void (Derive_1::*D_pointer)();
    D_pointer = &Derive_1::non_virtual_show;
    printf("%p\n", D_pointer);
    D_pointer = &Derive_1::virtual_show;
    printf("%p\n", D_pointer);
    D_pointer = &Derive_1::virtual_show_1;
    printf("%p\n", D_pointer);
    D_pointer = &Derive_1::virtual_show_2;
    printf("%p\n", D_pointer);
    cout << endl;
    
    //PART 4 call the virtual function through their address
    void (Base::*pointer1)();
    Base *p4 = new Derive_1;
    pointer1 = &Base::non_virtual_show;
    (p4->*pointer1)();
    pointer1 = &Base::virtual_show;
    printf("%p\n", pointer1);
    pointer1 = &Base::virtual_show_1;
    printf("%p\n", pointer1);
    pointer1 = &Base::virtual_show_2;
    printf("%p\n", pointer1);
    (p4->*pointer1)();
    (p4->*(&Base::virtual_show_2))();
    (p4->Base::virtual_show_2)();
    p4->Base::virtual_show_2();
    //pointer1 = &Derive_1::non_virtual_show; cannot convert 'void (Derive_1::*)' to 'void (Base::*)()' in assignment
    //pointer1 = &Derive_1::virtual_show; cannot convert 'void (Derive_1::*)' to 'void (Base::*)()' in assignment
    cout << endl;
    
    void (Base::*pointer2)();
    Derive_1 *p5 = new Derive_1;
    pointer2 = &Base::non_virtual_show;
    (p5->*pointer2)();
    pointer2 = &Base::virtual_show;
    printf("%p\n", pointer2);
    pointer2 = &Base::virtual_show_1;
    printf("%p\n", pointer2);
    pointer2 = &Base::virtual_show_2;
    printf("%p\n", pointer2);
    (p5->*pointer2)();
    (p5->*(&Base::virtual_show_2))();
    (p5->Base::virtual_show_2)();
    p5->Base::virtual_show_2();
    cout << endl;
    
    void (Derive_1::*pointer3)();
    Derive_1 *p6 = new Derive_1;
    pointer3 = &Base::non_virtual_show;
    (p6->*pointer3)();
    pointer3 = &Base::virtual_show;
    printf("%p\n", pointer3);
    pointer3 = &Base::virtual_show_1;
    printf("%p\n", pointer3);
    pointer3 = &Base::virtual_show_2;
    printf("%p\n", pointer3);
    (p6->*pointer3)();
    (p6->*(&Base::virtual_show_2))();
    (p6->Base::virtual_show_2)();
    p6->Base::virtual_show_2();
    
    return 0;
}
输出结果:

技术分享

首先是基本的解释虚函数:
看part 1 和 part 2
p2->non_virtual_show();
p2->virtual_show();
这两行代码说明了虚函数的不同之处,上一行在静态编联(编译阶段)中已经确定调用的函数,而下一行是动态编联,在程序运行阶段才确定调用哪个类中的函数,虽说p2指向基类,但是类对象在程序运行过程中才确定是派生类,这样通过虚函数就会调用派生类中的函数。
摘抄个内容吧:
实现动态联编需要三个条件:
1、 必须把动态联编的行为定义为类的虚函数。
2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。
3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。
定义虚函数的限制:
(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类析构函数定义为虚函数。因为,将基类析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
(2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
(3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。
(4)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类派生类中,也不能出现这种同名函数。

以上就是虚函数的基本东西了,那么part3和part4是什么东西?
其实part3part4就是这个问题:
技术分享
 为什么会输出不一样的结果呢?
百度百科上提到了virtual table,参考http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
于是写了part3part4研究看看,
运行结果:
技术分享
首先是part3的部分,发现不是虚函数的地址和虚函数的地址差得很多 ,而且,当我把基类的析构函数的virtual去掉之后的输出结果:
技术分享

 这似乎说明,虚函数的所谓地址只是virtual table中的相对地址(猜测是下标),因为间隔都是一样的,而且基类和派生类的相对地址是一样的(但这并不能说明地址一样,只是相对于virtual table起始距离一样)。不知道这种情况应该怎么解释。

Virtual Function

原文:http://blog.csdn.net/u012925008/article/details/44575335

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!