精华内容
下载资源
问答
  • 简述C++虚函数作用及底层实现原理 1.forewordC++是面向对象程序设计,其包括3项特点: (1)数据抽象:接口和实现分离 (2)继承:父类和子类 (3)多态:动态绑定本文讨论多态。当父类希望子类重新定义某些函数...

    简述C++虚函数作用及底层实现原理

    1.foreword

    C++是面向对象程序设计,其包括3项特点:
    (1)数据抽象:接口和实现分离
    (2)继承:父类和子类
    (3)多态:动态绑定

    本文讨论多态。

    当父类希望子类重新定义某些函数时,用virtual关键字声明为虚函数。

    当我们使用一个基类类型的引用或者指针,调用一个虚函数时就引发动态绑定/多态的发生。函数运行版本由传入的实参类型决定。可以用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。

    父类指针好像有“多种类型”。这是一种泛型技术,试图用不变的代码实现可变的算法,比如模板技术,虚函数技术等。

    引用或者指针的静态类型与动态类型不同这一事实,是C++支持多态的核心。

    上述这句话选自《C++ Primer》,颇有玄门正宗之感。复杂的技术根植于底层的原理,所以搞清原理方可深入浅出。

    当我们使用基类的引用、指针去调用基类中定义的一个虚函数时,并不知道该函数真正作用的对象是什么类型,可能是一个基类对象,也可能是一个派生类对象,这一切直到运行时才可知道。所以多态又称运行时绑定/动态绑定。

    对于非虚函数的调用在编译时即可确定,哪个对象,哪个方法,地址是确定的。

    2.虚函数底层实现原理

    当你记住上面的概念时,它仅是概念。但当真正了解底层原理后,发现其中妙不可言。

    如果让你来实现虚函数的功能?你会怎么实现?

    复杂的代码?高深的原理?其实C++中实现的非常接地气。

    虚函数是通过虚函数表和虚函数指针来实现的。

    该表一般位于某类型的对象实例在内存中的最开始的位置。

    单类继承

    class Base {
    public:
        virtual void f() { cout << "Base::f()" << endl; }
        virtual void g() { cout << "Base::g()" << endl; }
        virtual void h() { cout << "Base::h()" << endl; }
    };

    父类对象其在内存中布局示意如下:
    这里写图片描述

    虚函数表的尾部为虚函数表的结束结点。

    再定义一个子类,此时并不覆盖父类的虚函数:

    class Derived :public Base {
    public:
        virtual void f1() { cout << "Derived::f1()" << endl; }
        virtual void g1() { cout << "Derived::g1()" << endl; }
        virtual void h1() { cout << "Derived::g1()" << endl; }
    };

    这里写图片描述

    此时可以得知:
    (1)虚函数按照声明顺序放在表中;
    (2)父类的虚函数,排在子类虚函数之前。

    当我们把子类中的函数覆盖时:

    class Derived :public Base {
    public:
        // f() override
        void f() { cout << "Derived::f1()" << endl; }
        virtual void g1() { cout << "Derived::g1()" << endl; }
        virtual void h1() { cout << "Derived::g1()" << endl; }
    };

    这里写图片描述

    此时可以得知:
    (1)子类覆盖的虚函数,放在原来父类该虚函数的位置;所以当父类指针指向该子类对象时,调用方法就会调用子类重载的方法;
    (2)没有被覆盖的虚函数依旧。

    多类继承

    当发生多类继承时:

    这里写图片描述

    虚函数表内存排列示意如下:

    这里写图片描述

    此时可以得知:
    (1)每个继承的父类,都有自己的虚函数表;
    (2)子类虚函数,放在第一个声明顺序的父类的表中。

    当子类虚函数重写时,此时类的继承为:

    这里写图片描述

    子类将f( )函数重写,则内存中的排列为:

    这里写图片描述

    此时我们可以得知:
    (1)三个父类虚函数表中的f( )函数被替换为子类函数指针。因此当我们用任一静态类型的父类指针来指向子类时,调用f( )时就调用的子类的f( )。


    参考资料:
    [1] http://www.cnblogs.com/webary/p/4731457.html

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

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

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

    展开全文
  • 什么是C++虚函数虚函数作用和使用方法 我们知道,在同一类中是不能定义两个名字相同、参数个数和类型都相同的函数的,否则就是“重复定义”。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个...

    什么是C++虚函数、虚函数的作用和使用方法

    我们知道,在同一类中是不能定义两个名字相同、参数个数和类型都相同的函数的,否则就是“重复定义”。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型都相同而功能不同的函数。

    能否用同一个调用形式,既能调用派生类又能调用基类的同名函数。在程序中不是通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们。例如,用同一个语句“pt->display( );”可以调用不同派生层次中的display函数,只需在调用前给指针变量 pt 赋以不同的值(使之指向不同的类对象)即可。

    打个比方,你要去某一地方办事,如果乘坐公交车,必须事先确定目的地,然后乘坐能够到达目的地的公交车线路。如果改为乘出租车,就简单多了,不必查行车路线,因为出租车什么地方都能去,只要在上车后临时告诉司机要到哪里即可。如果想访问多个目的地,只要在到达一个目的地后再告诉司机下一个目的地即可,显然,“打的”要比乘公交车 方便。无论到什么地方去都可以乘同—辆出租车。这就是通过同一种形式能达到不同目的的例子。

    C++中的虚函数就是用来解决这个问题的。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

    (1)在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便被调用。
    在类外定义虚函数时,不必在定义virtual

    (2)在派生类中重新定义此函数,要求函数名,函数类型,函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。

    c++规定,当一个成员函数被声明为虚函数后,其派生类的同名函数都自动成为虚函数。因此在派生类重新声明该

    虚函数时,可以加virtual,也可以不加,但习惯上一般在每层声明该函数时都加上virtual,使程序更加清晰。

    如果再派生类中没有对基类的虚函数重新定义,则派生类简单的继承起基类的虚函数。

    (3)定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。
    (4)通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。

    #include<iostream>
    #include<string>
     
    using namespace std;
     
    class Student
    {
    	public:
    		Student(int , string, float);
    		void display();
    	protected:
    		int num;
    		string name;
    		float score;	
    };
    Student::Student(int n, string na, float s)
    {
    	num=n;
    	name=na;
    	score=s;
    }
    void Student::display()
    {
    	cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<endl;
    }
    class Graduate:public Student
    {
    	public:
    			Graduate(int , string , float, float);
    			void display();
     
    	private:
    			float pay;
    	
    };
    Graduate::Graduate(int n, string na, float s, float p):Student(n,na,s),pay(p)
    {
    }
    void Graduate::display()
    {
    	cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\npay:"<<pay<<endl;
     }
     
    int main()
    {
    	Student stud1(110,"SDL",99.8);
    	Graduate grad1(120,"CCT",88.9, 250.5);
    	
    	Student *p;
    	
    	p=&stud1;
    	cout<<"student:"<<endl;
    	p->display();
    	p=&grad1;
    	cout<<"graduate:"<<endl;
    	p->display();
    	
    	return 0;
    } 
    

    输出结果为:
    在这里插入图片描述
    此时没有将任何函数声明为虚函数,所以在Graduate类中diaplay()函数输出时没有pay的值,以为p指针是Student类的,本身Student不包括pay数据。

    但如果我们想输出pay的值,只要把Student类中的display函数声明为虚函数即可,只要把它改为virtual void display()声明为虚函数就行,输出的结果为:
    在这里插入图片描述

    展开全文
  • c++中虚函数作用

    2019-07-04 19:40:13
    参考链接 ... 类中普通虚函数作用,实现多态 #include<iostream> #include<stdlib.h> using namespace std; class A{ public: virtual void pri...

     

    参考链接

    https://blog.csdn.net/fyf18845165207/article/details/82697299

     

    类中普通虚函数作用,实现多态

    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    class A{
    public:
        virtual void print();//声明为虚函数
    };
    void A::print(){
        cout<<"this is A"<<endl;
    }
    class B:public A{
    public:
         void print();
    };
    void B::print(){
        cout<<"this is B"<<endl;
    }
    int main(){
        A a;
        B b;
        A* p1=new A;
        A* p2=new B;
        p1->print();
        p2->print();
        system("pause");
        return 0;
    }

    运行结果如下:实现多态 

    虚函数总结: 
    在实现多态的时候,不仅要有父类引用子类对象,还要有虚函数,我们只需把基类函数声明设为virtual,其派生类的相应函数也会成为虚函数。不需要在基类函数定义和派生类函数声明前再加关键字virtual. 
    纯虚函数也就是抽象函数,抽象函数所在的类为抽象类,只是一个特殊的类,为子类提供接口,抽象类无法实例化,只能通过继承机制,生成抽象类的非抽象派生类,再实例化。
     

     

     

    虚析构函数

    https://www.cnblogs.com/lit10050528/p/3874703.html

    总的来说虚析构函数是为了避免内存泄露,而且是当子类中会有指针成员变量时才会使用得到的。也就说虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数达到释放子类中堆内存的目的,而防止内存泄露的。

    代码:

    #include <iostream>
    
    using namespace std;
    
    class Base
    {
    public:
        Base(){}
        virtual ~Base()
        {
            cout << "Base Destructor." << endl;
        }
    private:
        int a, b;
    };
    
    class Derive : public Base
    {
    public:
        Derive()
        {
            pI = new int;
        }
        ~Derive()
        {
            cout << "Derive Destructor." << endl;
            // release memeory
            if(pI != NULL)
            {
                delete pI;
            }
        }
    private:
        int *pI;
    };
    
    int main(void)
    {
        {
            Base *pD = new Derive;
            delete pD;
        }
        int i;
        cin >> i;
    
        return 0;
    }

    从运行结果可以看到,这次执行了父类和子类的析构函数,那么就不会造成内存泄露了。

     

    对比总结

    1. 普通虚函数只执行子类实现的函数;

    2. 虚析构函数,同时执行子类和父类的析构函数;

    为什么这样设计?

    因为普通虚函数只需要重写(覆盖)原有父类的函数实现即可;而虚析构函数,涉及到类成员,而子类是集成了父类的成员的,所以虚析构函数也要被继承,才能保证成员的释放;这跟构造函数,子类会调用父类构造函数是一样的。

     

     

     

    展开全文
  • 虚函数作用

    万次阅读 多人点赞 2019-06-16 15:01:18
    从整体上来讲,虚函数作用主要是为了能够实现多态而设计的。虚函数作用可以借用一下进行说明: 虚函数作用:通过以下两个程序来进行解释! 可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时...
  • C++中虚函数作用

    2020-08-03 21:18:04
    C++中的虚函数作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在派生类中对基类定义的虚函数进行重写时,需要再派生类中声明该方法为虚方法。 当子类重新定义了父类的虚函数后,当父类的指针...
  • 一、什么是虚函数?...虚函数作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。下面来看一
  • C++中的虚函数作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。...
  • 虚函数作用和实现原理

    千次阅读 2018-04-02 12:11:33
    https://www.nowcoder.com/questionTerminal/1f67d4e2b6134c298e993e622181b3331、虚函数作用:简单讲即实现多态。 基类定义了虚函数,子类可以重写该函数,当子类重新定义了父类的虚函数后,父类指针根据赋给...
  • 一、虚函数 虚函数是C++用于实现多态(polymorphism)的机制,核心理念就是通过基类访问派生类定义的函数。定义虚函数是为了用基类的指针来调用子类的函数。 下面介绍的是虚函数的一个典型应用: #include using ...
  • 博客《Cpp 对象模型探索 —— 虚函数作用》中图片的原版文档,网址:https://blog.csdn.net/itworld123/article/details/102894752 。
  • 虚函数为了重载和多态的需要,在基类中是有定义的,即便定义是空,所以子类中可以重写也可以不写基类中的此函数! 纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数! 虚函数 引入原因:...
  • C++虚函数作用及实现原理(一)

    万次阅读 2018-07-05 00:27:49
    为什么会有虚函数的出现呢?这就不得不提到多态了 多态:专业的术语说就是:同一个实现接口,使用不同的实例而执行不同的操作。而简单的来说同一个事物的不同体现,比如我是老师的学生,是爸爸妈妈的女儿。 多态有...
  • 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 ...
  • 简单地说,那些被virtual关键字修饰的...虚函数作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。
  • 虚函数作用及使用方法

    千次阅读 多人点赞 2020-03-18 15:25:00
    我们知道,在同一类中是不能定义两个名字相同、参数个数和类型都相同的函数的,否则就是“重复定义”。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型都相同而功能不同的函数。 打个...
  • 1.事先阅读程序,给出其运行结果,上机验证虚函数作用。 有如下程序: #include #include using namespace std; class Student //定义基类 { public: Student(int,string,float); void display(); //声明...
  • c++中基类写成虚函数作用

    千次阅读 2015-08-22 22:23:33
    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:   有下面的两个类: class ClxBase { public:  ClxBase() {};  virtual ~...
  • 析构函数为虚函数作用

    千次阅读 2020-11-18 16:21:46
    如果要用继承,那么一定要让析构函数是虚函数 如果一个函数是虚函数,那么在子类中也要是虚函数 #include iostream.h class Base { public: Base(){ cout<<"Constructing Base";} // this is a ...
  • 多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层 函数不属于成员函数,是不能被继承的 2.为什么C++不支持构造函数为虚函数? 这个原因很简单,主要是从语义上考虑,所以不支持。因为...
  • 虚函数 2 之虚函数的定义

    千次阅读 2019-01-24 23:20:34
    虚函数作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。 虚函数的定义是在基类中进行的,它是在基类中在那些需要定义为虚函数的成员函数的声明中冠以...
  • 虚函数作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型(也...
  • C#中的虚函数作用

    千次阅读 2014-05-19 21:01:45
    先看一个例子: using System; using System.Collections.Generic;...可以认为JAVA中所有的方法都是方法。而C#中只有在基类的方法中加上 virtual关键字,然后在派生类中重写,在多态时才有效。
  • 虚函数作用是实现动态绑定的,也就是说程序在运行的时候动态的的选择合适的成员函数 那么,有哪些函数可以成为虚函数?那些函数不可以成为虚函数? 要成为虚函数必须满足两点,一就是这个函数依赖于对象调用,...
  • 因为虚函数作用是允许在派生类中对基类的虚函数重新定义。所以虚函数只能用于类的继承层次结构中。  一个成员函数被声明为虚函数后,在同一类族中的类不能再定义一个非virtual的但与该虚函数具有相同的参数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,831
精华内容 39,932
关键字:

虚函数的作用