精华内容
下载资源
问答
  • 主要介绍了C++中析构函数作用及其原理分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 1. virtual虚函数作用 实现C++三大特性之一的多态 当父类的某个函数,需要在子类中重写时,就在父类中定义为虚函数; 这样当定义一个父类指针指向子类时,就能动态地调用某子类的(被重写)函数; 纯虚函数: 父类中...

    虚函数的作用和实现原理


    1. virtual虚函数作用

    • 实现C++三大特性之一的多态
    • 当父类的某个函数,需要在子类中重写时,就在父类中定义为虚函数;
    • 这样当定义一个父类指针指向子类时,就能动态地调用某子类的(被重写)函数;

    纯虚函数: 父类中没有定义,而在子类中需要用到,就定义为:virtual void f() = 0;

    class A {
    public:
        virtual void func() = 0; // 这种写法叫纯虚函数
    };
    
    class B: public A {
    public:
        void func() {
            cout << "this is B" << endl;
        }
    };
    
    int main()
    {
        A *p = new B;
        p->func();
        return 0;
    }
    

    打印结果为:

    this is B
    

    2. 虚函数原理–虚函数表(virtual table)

    • 父类的实例化存储了一个虚函数指针(v_ptr),它指向了一张虚函数表(v_table),这张表记录了到每个子类的对应关系;当通过父类指针调用子类方法时,就会调用v_ptr和v_table;

    3. 构造函数与折构函数能否申明为虚函数?

    • 场景1: B *p = new B; (B是A的一个子类, 如下代码)
    • 首先明确调用顺序:
      • 构造函数:先调用父类的,再调用子类的;不可以为虚函数
      • 折构函数:先调用子类的,再调用父类的;可以是虚函数
    • 调用构造函数时,该子类的内存空间还未分配,父类的虚函数表没有任何意义;
    class A {
    public:
        A() {cout << "A()" << endl;}
        ~A() {cout << "~A()" << endl;}
    };
    
    class B: public A {
    public:
        B() {cout << "B()" << endl;}
        ~B() {cout << "~B()" << endl;}
    };
    
    int main()
    {
        B *p = new B;
        delete p;
        return 0;
    }
    

    执行结果:

    /Users/mac/CLionProjects/testC++/cmake-build-debug/testC_
    A()
    B()
    ~B()
    ~A()
    
    • 场景2:父类指针指向子类: A *p = new B;
    • 若A的折构函数不是虚函数:
      • delete p时,只释放了A的内存,会造成子类B的内存部分泄漏;
    • 若A的折构函数是虚函是:
      • 将先通过A的虚函数表找到B的折构函数,从而先释放B的内存,最后释放A;
    • 因此在这种场景下,推荐将父类的折构函数申明为虚函数
    展开全文
  • 虚函数作用和实现原理

    千次阅读 2018-04-02 12:11:33
    https://www.nowcoder.com/questionTerminal/1f67d4e2b6134c298e993e622181b3331、虚函数作用:简单讲即实现多态。 基类定义了虚函数,子类可以重写该函数,当子类重新定义了父类的虚函数后,父类指针根据赋给...
    文章总结自牛客网的评论。
    
    

    https://www.nowcoder.com/questionTerminal/1f67d4e2b6134c298e993e622181b333

    1、虚函数的作用:简单讲即实现多态。
    基类定义了虚函数,子类可以重写该函数,当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态地调用属于子类的该函数,且这样的函数调用是无法在编译器期间确认的,而是在运行期确认,也叫做迟绑定。
    2、底层实现原理:先来看看C++对象模型



    这个模型从结合上面2中模型的特点,并对内存存取和空间进行了优化。在此模型中,non static 数据成员被放置到对象内部,static数据成员, static and nonstatic 函数成员均被放到对象之外。对于虚函数的支持则分两步完成:


    1.每一个class产生一堆指向虚函数的指针,放在表格之中。这个表格称之为虚函数表(virtual table,vtbl)。


    2.每一个对象被添加了一个指针,指向相关的虚函数表vtbl。通常这个指针被称为vptr。vptr的设定(setting)和重置(resetting)都由每一个class的构造函数,析构函数和拷贝赋值运算符自动完成。


    另外,虚函数表地址的前面设置了一个指向type_info的指针,RTTI(Run Time Type Identification)运行时类型识别是有编译器在编译器生成的特殊类型信息,包括对象继承关系,对象本身的描述,RTTI是为多态而生成的信息,所以只有具有虚函数的对象在会生成

    展开全文
  • 简述C++虚函数作用及底层实现原理

    千次阅读 2016-06-12 22:15:05
    要点是要答出虚函数和虚函数表指针的作用。C++中虚函数使用虚函数 虚函数表指针实现,虚函数表是一个类的虚函数的地址表,用于索引类本身以及父类的虚函数的地 址,假如子类的虚函数重写了父类的虚函数,则...

    要点是虚函数表和虚函数表指针的作用。C++中虚函数使用虚函数表和 虚函数表指针实现,虚函数表是一个类的虚函数的地址表,用于索引类本身以及父类的虚函数的地 址,假如子类的虚函数重写了父类的虚函数,则对应在虚函数表中会把对应的虚函数替换为子类的 虚函数的地址;虚函数表指针存在于每个对象中(通常出于效率考虑,会放在对象的开始地址处), 它指向对象所在类的虚函数表的地址;在多继承环境下,会存在多个虚函数表指针,分别指向对应 不同基类的虚函数表。

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

    千次阅读 2018-05-27 15:49:36
    原文链接:https://blog.csdn.net/u011000290/article/details/50498683在C++中,多态是利用虚函数来实现的。比如说,有如下代码:[cpp] view plain copy#include &lt;iostream&gt; using namespace ...

    原文链接:https://blog.csdn.net/u011000290/article/details/50498683

    在C++中,多态是利用虚函数来实现的。比如说,有如下代码:

    [cpp]  view plain  copy
    1. #include <iostream>  
    2. using namespace std;  
    3. class Animal  
    4. {  
    5. public:  
    6.     void Cry()  
    7.     {  
    8.         cout << "Animal cry!" << endl;  
    9.     }  
    10. };  
    11. class Dog :public Animal  
    12. {  
    13. public:  
    14.     void Cry()  
    15.     {  
    16.         cout << "Wang wang!" << endl;  
    17.     }  
    18. };  
    19. void MakeAnimalCry(Animal& animal)  
    20. {  
    21.     animal.Cry();  
    22. }  
    23. int main()  
    24. {  
    25.     Dog dog;  
    26.     dog.Cry();  
    27.     MakeAnimalCry(dog);  
    28.     return 0;  
    29. }  

    输出如下图:

    这里定义了一个Animal类,Dog类继承该类,并覆盖了它的Cry方法。有一个MakeAnimalCry方法,传入了Animal的引用,传入了dog对象,但是输出确是Animal的输出。理想的情况下,用户希望传入的是dog对象,就该调用dog的Cry方法。要实现这种多态行为,需要将Animal::Cry()声明为虚函数。可以通过Animal指针或者Animal引用来访问Animal对象,这种指针或者引用可以指向Animal、Dog、Cat对象,而不需要关心它们具体指向的是哪种对象。修改代码如下:

    [cpp]  view plain  copy
    1. #include <iostream>  
    2. using namespace std;  
    3. class Animal  
    4. {  
    5. public:  
    6.     virtual void Cry()  
    7.     {  
    8.         cout << "Animal cry!" << endl;  
    9.     }  
    10. };  
    11. class Dog :public Animal  
    12. {  
    13. public:  
    14.     void Cry()  
    15.     {  
    16.         cout << "Wang wang!" << endl;  
    17.     }  
    18. };  
    19. class Cat:public Animal  
    20. {  
    21. public:  
    22.     void Cry()  
    23.     {  
    24.         cout << "Meow meow" << endl;  
    25.     }  
    26. };  
    27. void MakeAnimalCry(Animal& animal)  
    28. {  
    29.     animal.Cry();  
    30. }  
    31. int main()  
    32. {  
    33.     Dog dog;  
    34.     Cat cat;  
    35.     //dog.Cry();  
    36.     MakeAnimalCry(dog);  
    37.     MakeAnimalCry(cat);  
    38.     return 0;  
    39. }  

    修改后的输出如下:


    这就是多态的效果,将派生类对象视为基类对象,并执行派生类的Cry实现。如果基类指针指向的是派生类对象,通过该指针调用运算符delete时,即对于使用new在自由存储区中实例化的派生类对象,如果将其赋给基类指针,并通过该指针调用delete,将不会调用派生类的析构函数。这可能会导致资源未释放、内存泄露等问题,为了避免这种问题,可以将基类的析构函数声明为虚函数

    在上面的程序中,演示了多态的效果,即在函数MakeAnimalCry中,虽然通过Animal引用调用Cry方法,但是实际调用的确是Dog::Cry或者Cat::Cry方法。在编译阶段,编译器并不知道将要传递给该函数的是哪种对象,无法确保在不同的情况下执行不同的Cry方法。应该调用哪个Cry方法显然是在运行阶段决定的。这是使用多态的不可见逻辑实现的,而这种逻辑是编译器在编译阶段提供的。下面详细地说明一下虚函数的底层实现原理。

    比如说有下面的基类Base,它声明了N个虚函数:

    [cpp]  view plain  copy
    1. class Base  
    2. {  
    3. public:  
    4.     virtual void Func1()  
    5.     {  
    6.         //Func1的实现代码   
    7.     }  
    8.     virtual void Func2()  
    9.     {  
    10.         //Func2的实现代码   
    11.     }  
    12.     //Func3、Func4等虚函数的实现   
    13.     virtual void FuncN()  
    14.     {  
    15.         //FuncN的实现代码   
    16.     }  
    17. };  

    下面的Derived类继承了Base类,并且覆盖了除Func2之外的其他所有虚函数,

    [cpp]  view plain  copy
    1. class Derived:public Base  
    2. {  
    3. public:  
    4.     virtual void Func1()  
    5.     {  
    6.         //Func2覆盖Base类的Func1代码   
    7.     }  
    8.     //除去Func2的其他所有虚函数的实现代码   
    9.     virtual void FuncN()  
    10.     {  
    11.         //FuncN覆盖Base类的FuncN代码   
    12.     }  
    13. };  

    编译器见到这种继承层次结构后,知道Base定义了虚函数,并且在Derived类中覆盖了这些函数。在这种情况下,编译器将为实现了虚函数的基类和覆盖了虚函数的派生类分别创建一个虚函数表(Virtual Function Table,VFT)。也就是说Base和Derived类都将有自己的虚函数表。实例化这些类的对象时,将创建一个隐藏的指针VFT*,它指向相应的VFT。可将VFT视为一个包含函数指针的静态数组,其中每个指针都指向相应的虚函数。Base类和Derived类的虚函数表如下图所示:


    每个虚函数表都由函数指针组成,其中每个指针都指向相应虚函数的实现。在类Derived的虚函数表中,除一个函数指针外,其他所有的函数指针都指向本地的虚函数实现。Derived没有覆盖Base::Func2,因此相应的虚函数指针指向Base类的Func2的实现。这就意味着,当执行下面的代码时,编译器将查找Derived类的VFT,确保调用Base::Func2的实现:

    [cpp]  view plain  copy
    1. Derived objDerived;  
    2. objDerived.Func2();  

    调用被覆盖的方法时,也是这样:

    [cpp]  view plain  copy
    1. void DoSomething(Base& objBase)  
    2. {  
    3.     objBase.Func1();  
    4. }  
    5. int main()  
    6. {  
    7.     Derived objDerived;  
    8.     DoSomething(objDerived);  
    9. }  

    在这种情况下,虽然将objDerived传递给了objBase,进而被解读成一个Base实例,但该实例的VFT指针仍然指向Derived类的虚函数表,因此通过该VFT执行的是Derived::Func1.虚函数表就是通过上面的方式来实现C++的多态。

    要验证虚函数表的存在其实也很简单,可以通过比较同一个类,一个包含虚函数,一个不包含,对比其大小就知道了。

    [cpp]  view plain  copy
    1. #include <iostream>  
    2. using namespace std;  
    3. class Test   
    4. {  
    5. public:  
    6.     int a,b;  
    7.     void DoSomething()  
    8.     {   }   
    9. };  
    10. class Base  
    11. {  
    12. public:  
    13.     int a,b;  
    14.     virtual void DoSomething()  
    15.     {   }   
    16. };  
    17. int main()  
    18. {  
    19.     cout<<"sizeof(Test):"<<sizeof(Test)<<endl;  
    20.     cout<<"sizeof(Base):"<<sizeof(Base)<<endl;  
    21.     return 0;  
    22. }  

    执行输出如下:


    虽然两个类几乎相同,因为Base中的DoSomething方法是一个虚函数,编译器为Base类生成了一个虚函数表,并为其虚函数表指针预留空间,所以Base类占用的内存空间比Test类多了8个字节。



    展开全文
  • C++中虚函数作用和实现原理

    千次阅读 2018-05-31 21:28:32
    虚函数作用和实现原理 虚函数实现原理虚函数表、虚函数指针 虚函数作用:当调用一个虚函数时,被执行的代码必须调用函数的对象的动态类型相一致。 当一个类声明了虚函数或者继承了虚函数,这个类就会有...
  • C++虚函数作用及实现原理(一)

    万次阅读 2018-07-05 00:27:49
    为什么会有虚函数的出现呢?这就不得不提到多态了 多态:专业的术语说就是:同一个实现接口,使用不同的实例而执行不同的操作。而简单的来说同一个事物的不同体现,比如我是老师的学生,是爸爸妈妈的女儿。 多态有...
  • 简述C++虚函数作用及底层实现原理 1.forewordC++是面向对象程序设计,其包括3项特点: (1)数据抽象:接口实现分离 (2)继承:父类子类 (3)多态:动态绑定本文讨论多态。当父类希望子类重新定义某些函数...
  • C/C++虚函数和虚函数表概念及实现原理1. 概述2. 虚函数表构造过程3. 虚函数调用过程4. 多重继承 1. 概述 每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类...
  • c++虚函数实现原理

    千次阅读 2018-08-04 09:09:24
    C++中的虚函数作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...
  • c++中虚函数表的作用主要是实现了多态的机制。首先先解释一下多态的概念,多态是c++的特点之一,关于多态,简而言之就是 用父类的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种方法呢,...
  • 虚函数实现原理

    万次阅读 多人点赞 2018-09-02 10:28:21
    C++中的虚函数作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...
  • 虚函数:多态的实现原理

    千次阅读 2019-09-07 18:00:07
    C++ 中的虚函数作用主要是实现了多态的机制。关于多态,说白了就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数(当然引用也可以达到该目的,引用也是指针的另一种变种)。这种技...
  • 本文档详细介绍了C++中虚函数原理以及在何场景下要用到虚函数
  • C++常见面试题:虚函数实现原理

    千次阅读 2017-08-15 17:04:52
    转载地址:http://blog.csdn.NET/wanghaobo920/article/details/7674631前言C++中的虚函数作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类...
  • 这是比较专业术语解释C++虚函数作用文章:https://blog.csdn.net/iFuMI/article/details/51088091,基础比较好的可以看这篇 接下来是我个人的理解,因为可能面试也需要,特此记录一下。 众所周知,虚函数是用来...
  • 这篇文章主要介绍了c++中虚函数和纯虚函数的作用与区别,需要的朋友可以参考下 虚函数为了重载多态的需要,在基类中是有定义的,即便定义是空,所以子类中可以重写也可以不写基类中的此函数! 纯虚函数在...
  • 虚函数

    千次阅读 多人点赞 2015-12-17 22:37:05
    虚函数是面向对象编程函数的一种特定形态,是C++用于实现多态的一种有效机制。...在派生类中重新定义的函数应与虚函数具有相同的形参个数形参类型,(参数类型的顺序也要一致),以实现统一的接口。如果在派生
  • 然后,子类继承父类时,会获得继承下来的__vptr,再根据自己的类的情况兼容(修改虚函数表里的值、发生偏移等。于是,当我们构建具体的类时,若是基类类型,__vptr就会指向父类的vtable,若是子类类型,__vptr就会指
  • C++ 虚函数实现原理

    千次阅读 2015-08-05 20:24:39
    首先,我们要明白虚函数作用:简单讲就是实现多态。  基类定义了虚函数,子类可以重写该函数,当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态地调用属于子类的该函数,且这样的函数...
  • C++多态——虚函数,调用原理

    千次阅读 2018-07-01 16:37:40
    多态调用原理 什么是多态? 通俗的,一个事物有多种状态,在C++里是指一个基类成员函数被不同的派生类或者基类调用,有不同的结果。用基类的指针或引用操纵多个类型的能力被称为多态 多态分为静态多态...
  • C++中 的虚函数作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术 可以让父类的指针有“多种形态”,这是一种泛型技术...
  • C++中析构函数作用及其原理分析

    万次阅读 多人点赞 2018-08-21 17:24:43
    C++中的虚析构函数到底什么时候有用的,什么作用呢。 一.虚析构函数的作用  ...我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说...
  • 基类与派生类中有同名函数。在下面的程序中Student是基类,Graduate是派生类,它们都有display这个同名的函数。 #include <iostream> #include <string> using namespace std; //声明基类Student ...
  • 虚函数表工作原理 C++中的虚函数作用主要是实现了多态的机制关于多态简而言之就是用父类型别的指针指向其子类的实例然后通过父类的指针调用实际子类的成员函数这种技术可以让父类的指针有多种形态这是一种泛型技术...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,076
精华内容 14,430
关键字:

虚函数的作用和原理