• 虚函数与多态性



    C++调用虚函数的时候,要根据实例(即this指针指向的实例)中虚函数表指针得到虚函数表,再从虚函数表中找到函数的地址。
    #include<iostream.h> class shape {public: int a; shape(int t) { a=t; } virtual void area() { cout<<"shape "; } }; class circle: public shape { public: void area(); circle(int x):shape(x){} }; void circle::area() { cout<<" circle "; } void f(shape &h) {h.area(); } void main() { shape objs(1); f(objs); cout<<objs.a; circle objc(2); f(objc); cout<<objc.a<<endl; }

    class A
    {
    public:
        virtual void f();
        virtual void g();
    private:
        int a
    };
    class B : public A
    {
    public:
        void g();
    private:
        int b;
    };
    //A,B的实现省略
    因为A有virtual void f(),和g(),所以编译器为A类准备了一个虚表vtableA,内容如下:
    A::f 的地址
     
    A::g 的地址
     
    B因为继承了A,所以编译器也为B准备了一个虚表vtableB,内容如下:
    A::f 的地址 
    B::g 的地址
    注意:因为B::g是重写了的,所以B的虚表的g放的是B::g的入口地址,但是f是从上面的A继承下来的,所以f的地址是A::f的入口地址。
    然后某处有语句 B bB;的时候,编译器分配空间时,除了A的int a,B的成员int b;以外,还分配了一个虚指针vptr,指向B的虚表vtableB,bB的布局如下:
    vptr : 指向B的虚表vtableB
     
    int a: 继承A的成员
     
    int b: B成员
     
    当如下语句的时候:
    A *pa = &bB;
    pa的结构就是A的布局(就是说用pa只能访问的到bB对象的前两项,访问不到第三项int b)
    那么pa->g()中,编译器知道的是,g是一个声明为virtual的成员函数,而且其入口地址放在表格(无论是vtalbeA表还是vtalbeB表)的第2项,那么编译器编译这条语句的时候就如是转换:call *(pa->vptr)[1](C语言的数组索引从0开始哈~)。
    这一项放的是B::g()的入口地址,则就实现了多态。(注意bB的vptr指向的是B的虚表vtableB)
    另外要注意的是,如上的实现并不是唯一的,C++标准只要求用这种机制实现多态,至于虚指针vptr到底放在一个对象布局的哪里,标准没有要求,每个编译器自己决定。我以上的结果是根据g++ 4.3.4经过反汇编分析出来的。
    2、两种多态实现机制及其优缺点
    除了c++的这种多态的实现机制之外,还有另外一种实现机制,也是查表,不过是按名称查表,是smalltalk等语言的实现机制。这两种方法的优缺点如下:
    (1)、按照绝对位置查表,这种方法由于编译阶段已经做好了索引和表项(如上面的call *(pa->vptr[1]) ),所以运行速度比较快;缺点是:当A的virtual成员比较多(比如1000个),而B重写的成员比较少(比如2个),这种时候,B的vtableB的剩下的998个表项都是放A中的virtual成员函数的指针,如果这个派生体系比较大的时候,就浪费了很多的空间。
    http://blog.sina.com.cn/s/blog_3c6889fe0100qpac.html
  • 相关阅读:
    mysql错误:java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone.
    MyBatis中id回填的两种方式
    springboot项目打war包流程
    Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include springcloudstarterloadbalancer?
    idea thymeleaf页面变量报错解决
    项目编码流程
    逻辑删除
    mysql 连接url中需要添加useUnicode=true&characterEncoding=UTF8
    【转】[wp7应用内截图]Taking a screenshot from within a Silverlight #WP7 application
    Wp7客户端与Webservice的数据传输,json的序列化与反序列化
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4491358.html
Copyright © 2020-2023  润新知