精华内容
下载资源
问答
  • 虚函数的实现原理

    千次阅读 2019-03-10 18:05:42
    虚函数的实现原理: 虚函数的用法:可以让派生类重写基类的成员函数实现多态。虚函数实现多态的机制,严格来说是动态多态,是在出现运行的时候实现的。 虚函数的实现原理:每个虚函数都会有一个与之对应的虚函数表...

    虚函数的实现原理:

    虚函数的用法:可以让派生类重写基类的成员函数实现多态。虚函数实现多态的机制,严格来说是动态多态,是在出现运行的时候实现的。

    虚函数的实现原理:每个虚函数都会有一个与之对应的虚函数表,该虚函数表的实质是一个指针数组,存放的是每一个对象的虚函数入口地址。对于一个派生类来说,他会继承基类的虚函数表同时增加自己的虚函数入口地址,如果派生类重写了基类的虚函数的话,那么继承过来的虚函数入口地址将被派生类的重写虚函数入口地址替代。那么在程序运行时会发生动态绑定,将父类指针绑定到实例化的对象实现多态。

     更多详见:https://blog.csdn.net/xiejingfa/article/details/50454819

    展开全文
  • C++ 之虚函数的实现原理 带有虚函数的类,编译器会为其额外分配一个虚函数表,里面记录的使虚函数的地址,当此类被继承时,子类如果也写了虚函数就在子类的虚函数表中将父类的函数地址覆盖,否则继承父类的虚函数...

    c++的多态使用虚函数实现,通过“晚绑定”,使程序在运行的时候,根据对象的类型去执行对应的虚函数。

    C++ 之虚函数的实现原理

    带有虚函数的类,编译器会为其额外分配一个虚函数表,里面记录的使虚函数的地址,当此类被继承时,子类如果也写了虚函数就在子类的虚函数表中将父类的函数地址覆盖,否则继承父类的虚函数地址。

    实例化之后,对象有一个虚函数指针,虚函数指针指向虚函数表,这样程序运行的时候,通过虚函数指针找到的虚函数表就是根据对象的类型来指向的了。

     

    转载于:https://www.cnblogs.com/bewolf/p/9352116.html

    展开全文
  • C++虚函数的实现原理

    万次阅读 2017-11-08 22:49:34
    C++中的虚函数主要是用来实现多态(面向对象三大特性之一)。 下面是一个实现多态错误例子: // 基类 // class Base { public: Base() { printf("Call Base::Base()\n"); } ~Base() { } ...

    一. 虚函数介绍

    C++中的虚函数主要是用来实现多态(面向对象的三大特性之一)的。
    下面是一个实现多态的错误例子:

    // 基类
    //
    class Base {
    public:
        Base() {
            printf("Call Base::Base()\n");
        }
    
        ~Base() {
    
        }
    
        void Name() {
            printf("Call Base::Name()\n");
        }
    };
    
    // 派生类
    //
    class Derive : public Base {
    public:
        Derive() {
            printf("Call Derive::Derive()\n");
        }
    
        ~Derive() {
    
        }
    
        void Name() {
            printf("Call Derive::Name()\n");
        }
    };
    
    int main()
    {
        Base* pBase = new Derive();
        pBase->Name();
    
        delete pBase;
        return 0;
    }

    程序输出:

    Call Base::Base()
    Call Derive::Derive()
    Call Base::Name()

    输出内容的第3行为:Call Base::Name(),并不是期望的Call Derive::Name()
    因为void Name()函数不是虚函数,所以pBase->Name()调用的是基类的Name()函数,并不是我们所期望的派生类Derive的Name()函数。 如果将基类中void Name()改成虚函数virtual void Name(),程序输出就会和我们期望的一样:

    // 基类
    //
    class Base {
    public:
        Base() {
            printf("Call Base::Base()\n");
        }
    
        ~Base() {
            printf("Call Base::~Base()\n");
        }
    
        virtual void Name() {
            printf("Call Base::Name()\n");
        }
    };

    二、 虚析构函数

    virtual不仅可以修饰成员函数,也可以用来修饰析构函数,也就是我们常说的虚析构函数。 下面的例子中的基类的析构函数没有使用virtual修饰,我们先执行程序,观察运行结果(类似上面的程序,只是在析构函数中多加入了输出打印语句)。

    // 基类
    //
    class Base {
    public:
        Base() {
            printf("Call Base::Base()\n");
        }
    
        ~Base() {
            printf("Call Base::~Base()\n");
        }
    
        virtual void Name() {
            printf("Call Base::Name()\n");
        }
    };
    
    // 派生类
    //
    class Derive : public Base {
    public:
        Derive() {
            printf("Call Derive::Derive()\n");
        }
    
        ~Derive() {
            printf("Call Derive::~Derive()\n");
        }
    
        void Name() {
            printf("Call Derive::Name()\n");
        }
    };
    
    int main()
    {
        Base* pBase = new Derive();
        pBase->Name();
    
        delete pBase;
        return 0;
    }

    程序输出:

    Call Base::Base()
    Call Derive::Derive()
    Call Derive::Name()
    Call Base::~Base()

    从输出内容的第4行可以看到,执行delete pBase语句只有基类Base类的析构函数被调用了,而派生类Derive的析构函数却没有被调用。如果此时派生类Derive中有需要在析构函数执行的代码(如内存释放,句柄关闭等),这些代码将不会执行,有可能就会造成内存泄漏、句柄泄漏、逻辑错误等问题。

    正确的做法是:使用virtual修饰基类的析构函数,即虚析构函数。

    // 基类
    //
    class Base {
    public:
        Base() {
            printf("Call Base::Base()\n");
        }
    
        virtual ~Base() {
            printf("Call Base::~Base()\n");
        }
    
        virtual void Name() {
            printf("Call Base::Name()\n");
        }
    };

    此时程序输出为:

    Call Base::Base()
    Call Derive::Derive()
    Call Derive::Name()
    Call Derive::~Derive()
    Call Base::~Base()

    调用delete pBase之后,先执行了派生类Derive的析构函数,然后执行基类Base的析构函数。

    《C++API设计》一书中有明确的说到:“如果希望一个类可以被继承,那么就应该将它的析构函数使用virtual修饰;反过来可以理解为,如果一个类的析构函数不是虚的,那么这个类是被设计为不可继承的。”

    二. 虚函数的实现原理

    2.1 实现原理

    C++的虚函数是使用虚函数表(即指针数组,也就是指针的指针)来实现的。 只要在类中声明了虚函数,编译器就会在类的对象中自动生成一个虚函数表,但一个对象最多只有一个虚函数表,不管这个类声明了多少个虚函数。虚函数表是针对于类的对象的。

    2.2 虚函数表(指针)存储位置

    不同的编译器将自动生成的虚函数表指针存放的位置不同,有的存放在类对象所占内存的起始位置,有的存放在类对象所占内存的末尾。 可以通过如下代码来判断:

    // 返回值: ture  - 虚函数指针存放在对象内存起始位置
    //         false - 虚函数指针存放在对象内存末尾位置
    //
    bool VirtualTableAtFirst() {
        class _C {
        public:
            char _i;
            virtual void _f() {
            }
        };
    
        _C c;
        char * p1 = reinterpret_cast<char*>(&c);
        char * p2 = reinterpret_cast<char*>(&c._i);
    
        return p1 != p2;
    }

    通过MSVC2015编译运行,返回true, 说明MSVC编译器是将虚函数表指针放置在类对象内存的起始位置处。

    2.3 虚函数表存储方式

    既然知道了C++是使用虚函数表的形式来实现虚函数的,那个虚函数表中的数据是以何种形式来存储的了? 现在我们根据类的继承方式的不同来分别说明。

    1. 单继承无重载

    类结构如图,Derive继承于Base,但Derive没有重载Base类中的任何函数。

    需要说明的是,函数f(), g(), h(), f1(), g1(), h1() 均为虚函数,这个在图上没有明确的写出来,后面的图也是一样。

    这里写图片描述

    这时Base b; 对象b的虚函数表为:
    这里写图片描述

    Derive d; 对象d的虚函数表为:
    这里写图片描述

    2. 单继承有重载

    Derive重载Base类中的f()函数:
    这里写图片描述

    这时Base b; 对象b的虚函数表不变,无论继承于它派生类如何重载,都不会影响基类的虚函数:
    这里写图片描述

    Derive d; 对象d的虚函数表为:
    这里写图片描述

    派生类中重载基类的f()函数指针替换了原来基类中虚函数Base::f()的指针; 派生类中其他的虚函数存放在基类虚函数之后。

    3. 多继承无重载

    这里写图片描述

    此时,Derive d; 对象d的虚函数表为:
    这里写图片描述

    派生类自己的虚函数存放在第一个基类的虚函数表的最后面。

    4. 多继承有重载

    这里写图片描述

    此时,Derive d; 对象d的虚函数表为:
    这里写图片描述

    图片引用自 http://blog.csdn.net/haoel/article/details/1948051

    展开全文
  • c++虚函数的实现原理

    2020-04-21 22:20:57
    c++虚函数是通过虚函数表来实现的,当一个类里含有虚函数时,编译器会给这个类分配一个虚函数表,虚函数表里存放的是虚函数的地址。当该类被继承时,其子类也会继承基类的虚函数表。 比如基类含有一个虚函数 f(), ...

    C++虚函数实现原理

    c++虚函数是通过虚函数表来实现的,当一个类里含有虚函数时,编译器会给这个类分配一个虚函数表,虚函数表里存放的是虚函数的地址。当该类被继承时,其子类也会继承基类的虚函数表。
    比如基类含有一个虚函数 f(), 子类含有一个虚函数g();基类的虚函数表里存放的就是函数f的地址,而子类的虚函数表里第一位存放的是基类函数f的地址,第二位存放的是函数g的地址。
    当子类虚函数覆盖基类虚函数时(参考c++重载,覆盖,隐藏),子类虚函数表中该虚函数的位置就存放到原先基类虚函数的位置,这样基类指针指向子类对象时,调用基类虚函数实际就会调用子类的虚函数,这就实现了多态。
    在c++中,虚函数表存放在内存中的只读数据段(.rodata)中,也就是常量区;虚函数存放在代码段(.text),也就是代码区。

    拓展
    (1)析构函数为什么要设置为虚函数?

    当一个类被继承,基类指针指向其子类对象时,在释放该基类指针的时候,只调用了基类的析构函数,会导致子类内存未被释放,导致内存泄漏;

    (2)如上所说,那c++中默认析构函数为什么不是虚函数?

    因为虚函数是通过虚函数表来实现的,而虚函数表在内存中占用了空间,当一个类不会被继承的时候,就无须考虑上述(1)中的情况,减少内存开销。

    展开全文
  • 虚函数的实现原理【虚函数作用】【动态联编】【虚函数表/指针 创建时机、作用、存放位置】 文章目录虚函数的实现原理【虚函数作用】【动态联编】【虚函数表/指针 创建时机、作用、存放位置】0 - 前言1 - 虚函数的...
  • 2020/08/04在华为面试过程中被问到:“虚函数的实现原理是什么?”,那一刻我懵了,在面试结束后,我查询了一下相关的文章,发现我曾经看过这个知识点,只不过长时间不使用,已经忘记了,现在重新查资料再记录一遍。...
  • 文中讲述的原理是推理和探讨 , 和现实中的实现不一定完全相同 。 C++ 的 虚函数 , 编译器 会 生成一个 虚函数表 。 虚函数表, 实际上是 编译器 在 内存 中 划定 的 一块 区域, 用于存放 类 的 虚函数 的 ...
  • 虚函数是实现多态的基础,在定义基类虚函数时,会为该基类分配一个虚函数表,虚函数表记录了虚函数的地址。 子类继承基类时,如果重写了虚函数,则会覆盖这个地址,形成新的虚函数表,否则就继承基类的虚函数地址。...
  • C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...
  • 1、对于C++中的虚函数一直都是靠着死记硬背的方式在使用,今天特地查阅了一下它的实现原理。 2、虚函数:C++中为了实现多样性的一个工具。使用virtual关键字修饰的函数即为虚函数,派生类自动继承虚函数性质。使用...
  • 这里有一篇博客写很不错:c++虚函数表解析 解析 typedef void(*Fun)(void);// 这是将Fun定义为一个指向 void (void) 函数类型函数指针 &b;// 得到对象地址(开头) (int*)(&b);// 虚函数地址存在...
  • 原文地址:https://www.cnblogs.com/malecrab/p/5572730.html1. 概述简单地说,每一个含有虚函数(无论是其本身,还是继承而来类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应函数指针...
  • 这是比较专业术语解释C++虚函数的作用文章:https://blog.csdn.net/iFuMI/article/details/51088091,基础比较好的可以看这篇 接下来是我个人的理解,因为可能面试也需要,特此记录一下。 众所周知,虚函数是用来...
  • 对于每一个有虚函数的类来说,它都有一个属于自己的虚表(vtable),而且每一个类只有唯一的一个vtable 这个虚表,实质上来说是一个函数指针数组,该数组记录了所有虚函数的函数指针。 在上面的代码中,...
  • C++覆盖(虚函数的实现原理

    千次阅读 2016-10-14 22:13:33
    还会生成一个虚函数表指针成员,这个虚函数表指针与虚函数表同时出现,虚函数表只有一个,而虚函数表指针指向虚函数表的首地址,在虚函数表中定义了一个函数指针,这个函数指针指向了计算面积函数的首地址,...
  • 讨论虚拟函数的技术内幕——后期联编(Late binding), 一,进入内存首先,一个含有虚拟函数的类在内存中的结构。假设一个这样的类: class CShape{ int b1;public: void MyTest() { cout <<"CShape::MyTest...
  • 1.总结虚函数的实现原理: 当类中有虚函数或者虚析构函数时,在实例化类的对象时,对象内存中除了成员变量的大小,还有一个虚函数表指针,而且虚函数表指针放在内存的最前面,虚函数表指针会指向一个...
  • 目录 2-7虚函数与虚析构函数实现原理 ...1.虚函数的实现原理 (1)引入概念:函数指针。 ​ 指向函数的指针——函数指针。 函数指针指向函数的内存地址。 (2)多态的实现原理 ​ 虚函数表指针 ​ vftable_ptr,4字...
  • C++ 多态(1): 虚函数实现原理

    多人点赞 2019-07-09 15:47:42
    1虚函数实现原理 2 代码示例1 3 代码示例2 参考资料 多态 多态指相同对象接收到不同消息或不同对象收到相同消息时产生不同动作。 多态分为静态多态和动态多态。 (1) 静态多态也称为早绑定。 (2) 动态...
  • 前言:在博客看到一位博主写的关于虚函数的实现原理写得通俗易懂,特别好,直接转载过来学习,这里没有原博主的博客链接,因为看到的只是另一个博主的对其的转载,而且并没有附上原博的链接。 正文:C++中的虚函数的...
  • C/C++杂记:虚函数的实现的基本原理 1. 概述 简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例: 其中: B的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,338
精华内容 535
关键字:

虚函数的实现原理