精华内容
下载资源
问答
  • C++ 虚函数理解

    2021-01-20 17:25:43
    C++虚函数理解 虚函数 虚函数例子 虚函数查看方法(VS2017) 虚函数的实现原理 一般继承(无虚函数覆盖) 一般继承(有虚函数覆盖) 多重继承下的虚函数 多重继承(无虚函数覆盖) 多重继承(有虚函数覆盖) 纯虚函数 ...

    虚函数

    C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态“。

    虚函数主要解决的是C++中的多态这一特性。多态分为两类

    • 静态多态: 函数重载和运算符重载属于静态多态,复用函数名
    • 动态多态: 派生类和虚函数实现运行时多态

    静态多态和动态多态区别:

    • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
    • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

    虚函数例子

    //基类
    class Base {
    public:
    	virtual void f() {
    		cout << "Base::f()" << endl;
    	}
    };
    //子类继承基类
    class Son :public Base {
    public:
    	virtual void f() {
    		cout << "Son::f()" << endl;
    	}
    };
    
    void test() {
    	Base *b;
    	b = new Son;
    	b->f();
    	b->g();
    }
    
    int main() {
    	test();
    	system("pause");
    	return 0;
    }
    

    Base作为基类,在Base中只定义了虚函数f(),在子类Son中重定义了f()的实现,即使我们定义的都是父类Base,将Base初始化指向一个子类Son(注意这里必须是指针)Base *b = new Son。这样做的好处是,我们还可以定义Son2、Son3都是继承自Base,他们有各自的f()的实现,我们可以统一都定义为Base *b,但是在开辟堆的时候,可以开辟不同的子类,例如:

    Base *b1 = new Son1;
    Base *b2 = new Son2;
    

    这样就可以实现多态。

    虚函数查看方法(VS2017)

    在cmd中找到VS2017的开发人员命令提示符 -> 进入cpp所在文件路径 ->输入
    cl /d1 reportSingleClassLayout类名 文件名.cpp
    例如:
    cl /d1 reportSingleClassLayoutBase 虚函数.cpp

    虚函数的实现原理

    我们都知道,如果一个类是空(没有成员也没有方法),类的sizeof是1。而如果一个类中只有一个虚函数,他的sizeof是4,正好是一个指针的大小,这个指针就是vfptr,虚函数指针,指向的是虚函数表中的虚函数。虚函数表为vftable。

    可以看到Base类,他的vfptr实际上指向了vftable中的某一项,两个虚函数f、g,分别在vftable中占据一项,调用的时候,利用vfptr去vftable中找到对应的函数地址进行调用。
    在这里插入图片描述
    同样的,我们再来看看Son类
    在这里插入图片描述
    可以看到,在子类Son中重写的虚函数,其实就是更新了vftable表中的函数,直接替代掉了父类中的函数,所以我们用子类去初始化父类,在调用函数,调用到的就是子类的函数,而不再是父类的函数。

    一般继承(无虚函数覆盖)

    在这里插入图片描述
    对于这种一般继承,子类没有重写父类的虚函数,虚函数表是这样的
    在这里插入图片描述

    1)虚函数按照其声明顺序放于表中。
    2)父类的虚函数在子类的虚函数前面

    一般继承(有虚函数覆盖)

    在这里插入图片描述
    对于这种子类有重写父类的虚函数(我们上面的例子),虚函数表会发生变化:
    在这里插入图片描述

    1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
    2)没有被覆盖的函数依旧。

    多重继承下的虚函数

    多重继承就很简单了,C++允许一个类继承多个类,因此可以让一个Son继承Base1、Base2,他们的虚函数关系就是简单的相加,如果有同名的,全部覆写。
    例子:

    //基类1
    class Base1 {
    public:
    	virtual void f() {
    		cout << "Base1::f()" << endl;
    	}
    	virtual void g() {
    		cout << "Base1::g()" << endl;
    	}
    };
    //基类2
    class Base2 {
    public:
    	virtual void f() {
    		cout << "Base2::f()" << endl;
    	}
    	virtual void g() {
    		cout << "Base2::g()" << endl;
    	}
    };
    //子类继承基类
    class Son :public Base1, public Base2 {
    public:
    	virtual void f() {
    		cout << "Son::f()" << endl;
    	}
    	virtual void h() {
    		cout << "Son::h()" << endl;
    	}
    };
    

    子类Son继承了父类Base1、Base2,但是只对父类的f()进行了重写,新引入了一个虚函数h(),我们可以看到此时的虚函数表:
    在这里插入图片描述
    他有两个父类,所以划分了两个虚函数表Base1和Base2,两个指针vfptr分别指向。Base1中的f()和Base2中的f()都被Son重写的f()覆盖了,但是g()保留了,而且子类新引入的h()添加到了Base1表的最后。

    用图例简单理解下:

    多重继承(无虚函数覆盖)

    在这里插入图片描述
    对应的虚函数表:
    在这里插入图片描述

    1) 每个父类都有自己的虚表。
    2) 子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的)

    多重继承(有虚函数覆盖)

    在这里插入图片描述
    对应的虚函数表:
    在这里插入图片描述

    1)对于同名的(子类重写的虚函数),直接替换虚函数表中的父类
    2)如果子类重写的虚函数只有部分父类有,则只替换那部分父类(按照虚函数名,只要子类重写了,就要替换父类中同名的,一切以子类重写的为准)
    3)子类中新定义的虚函数直接放到了第一个父类的表中。(同样的,第一个父类是按照声明顺序来判断的)

    纯虚函数

    在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
    因此可以将虚函数改为纯虚函数
    当类中有了纯虚函数,这个类也称为抽象类。抽象类的特点:

    1.无法实例化对象
    2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类

    纯虚函数语法virtual 返回值类型 函数名 (参数列表)= 0 ;
    示例:virtual void f() = 0;

    展开全文
  • 虚函数理解

    2021-11-11 09:49:46
    虚函数中默认参数 /** * @file first_example.cpp * @brief 虚函数中默认参数 * 规则:虚函数是动态绑定的,默认参数是静态绑定的。默认参数的使用需要看指针或者应用本身的类型,而不是对象的类型! * @author ...

    虚函数中默认参数

    /**
     * @file first_example.cpp
     * @brief 虚函数中默认参数
     * 规则:虚函数是动态绑定的,默认参数是静态绑定的。默认参数的使用需要看指针或者应用本身的类型,而不是对象的类型!
     * @author 光城
     * @version v1
     * @date 2019-07-24
     */
    
    #include <iostream> 
    using namespace std;
    
    class Base
    {
    public:
        virtual void fun ( int x = 10 )
        {
            cout << "Base::fun(), x = " << x << endl;
        }
    };
    
    class Derived : public Base
    {
    public:
        virtual void fun ( int x=20 )
        {
            cout << "Derived::fun(), x = " << x << endl;
        }
    };
    
    
    int main()
    {
        Derived d1;
        Base *bp = &d1;
        bp->fun();  // 10
        return 0;
    } 
    
    Derived::fun(), x = 10
    

    4.可以不可以¶

    • 静态函数可以声明为虚函数吗?

    原因主要有两方面:

    (1)静态函数不可以声明为虚函数,同时也不能被const 和 volatile关键字修饰

    static成员函数不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义

    虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,静态成员函数没有this指针,所以无法访问vptr。

    (2)构造函数可以为虚函数吗?

    构造函数不可以声明为虚函数。同时除了inline|explicit之外,构造函数不允许使用其它任何关键字。

    为什么构造函数不可以为虚函数?

    尽管虚函数表vtable是在编译阶段就已经建立的,但指向虚函数表的指针vptr是在运行阶段实例化对象时才产生的。 如果类含有虚函数,编译器会在构造函数中添加代码来创建vptr。 问题来了,如果构造函数是虚的,那么它需要vptr来访问vtable,可这个时候vptr还没产生。 因此,构造函数不可以为虚函数。

    我们之所以使用虚函数,是因为需要在信息不全的情况下进行多态运行。而构造函数是用来初始化实例的,实例的类型必须是明确的。 因此,构造函数没有必要被声明为虚函数。

    (3)析构函数可以为虚函数吗?

    析构函数可以声明为虚函数。如果我们需要删除一个指向派生类的基类指针时,应该把析构函数声明为虚函数。 事实上,只要一个类有可能会被其它类所继承, 就应该声明虚析构函数(哪怕该析构函数不执行任何操作)。

    展开全文
  • virtual 虚函数理解

    2021-08-16 14:19:06
    #include <iostream> using namespace std; class A { public: A() {f1();} void f() {f1();} virtual void f1() { printf("a");} }; class B:public A { public: void test() { f();...in.
    #include <iostream>
    using namespace std;
    
    class A
    {
        public:
            A() {f1();}
            void f() {f1();}
            virtual void f1() { printf("a");}
    };
    class B:public A
    {
        public:
          void test() { f();}
          void f1() {printf("b");}
    
    };
    
    int main()
    {
         B  b;
         b.test();
         return 0;
    }

    输出ab

    展开全文
  • 虚函数通俗理解,使用虚函数的场景,小白必看 1、为何要用虚函数。 网上有许多关于介绍虚函数理解,或是写一堆代码,但是,对于小白而言,很难理解虚函数的用处,以及在什么情况下用。 一句话说明虚函数的使用场景...

    虚函数通俗理解,使用虚函数的场景,小白必看

    1、为何要用虚函数。

    网上有许多关于介绍虚函数的理解,或是写一堆代码,但是,对于小白而言,很难理解虚函数的用处,以及在什么情况下用。

    一句话说明虚函数的使用场景:父类决定调用时机,子类决定具体实现。

    举个每天八点起床穿衣的例子,假设我们每天八点早上都要起床,穿衣服。而穿衣事件,都发生在早上八点。那么,我们可以将穿衣服这个函数的调用时机在父类中确定,也就是每天八点会调用穿衣函数。而具体穿什么衣服,每天都不一样,每天穿什么样的衣服,就在子类中具体实现,用代码表示就是:

    class father
    {
    public:
    	void clock_8() //每天8点钟的时候
    	{
    		//执行穿衣函数
    		dress();
    	}
    	//穿衣函数,是个纯虚函数,具体实现在子类中实现
    	//这样,父类就决定了,这个穿衣函数的调用时机
    	virtual void dress() = 0;
    };
    
    class child1 : public father
    {
    public:
    	//子类决定了,穿衣函数的具体实现
    	virtual void dress() 
    	{
    		cout << "穿红衣服" << endl;
    	}
    };
    
    int main()
    {
    	child1 c;
    	//这样子类,每天起床时,都会调用,穿衣服
    	c.clock_8();
    	return 0;
    }
    

    我们在使用一些官方库的时候,比如使用Qt时,绘图事件这个函数的调用时机有很多,比如改变窗口的大小,点击窗口中的按钮,都会触发绘图事件并调用绘图函数。而这些调用时机我们很难自己去确定,这时,Qt官方库会帮我们确定调用的时机。

    而具体需要绘制什么样的内容,需要我们自己去实现,这时,C++为我们提供了虚函数来实现这个需求。

    2、虚函数若干问题

    1、虚函数的类内实现
    子类实现虚函数,可以加virtual关键字,也可以不加virtual关键字

    class CFather
    {
    public:
    	virtual void func()
    	{
    		cout << "父类 func" << endl;
    	}
    };
    
    class CChildren : public CFather
    {
    public:
    
    	//子类的virtual 关键字,加不加效果一样,建议加上
    	virtual void func()
    	{
    		cout << "子类 func" << endl;
    	}
    };
    

    2、虚函数的类外实现
    类外实现,类内先申明,类外不写virtual关键字

    class CFather
    {
    public:
    	virtual void func()
    	{
    		cout << "父类 func" << endl;
    	}
    };
    
    class CChildren : public CFather
    {
    public:
    	//类内申明
    	virtual void func();
    };
    
    //类外实现,类内先申明,类外不写virtual关键字
    	void CChildren::func()
    	{
    		cout << "子类 func" << endl;
    	}
    

    3、纯虚函数
    父类有纯虚函数,父类变成抽象类,是无法实例对象的

    class CFather
    {
    public:
    //纯虚函数格式
    	virtual void func()=0;
    };
    
    class CChildren : public CFather
    {
    public:
    	//子类的virtual 关键字,加不加效果一样,建议加上
    	virtual void func()
    	{
    		cout << "子类 func" << endl;
    	}
    };
    int main()
    {
    	//报错,抽象类无法实例对象
    	//CFather far;
    }
    
    

    4、子类指针赋值给父类
    这种操作是将子类的指针赋值给父类,这种操作比较特殊

    class CFather
    {
    public:
    	virtual void func()
    	{
    		cout << "父类 func" << endl;
    	}
    };
    
    class CChildren : public CFather
    {
    public:
    
    	//子类的virtual 关键字,加不加效果一样,建议加上
    	virtual void func()
    	{
    		cout << "子类 func" << endl;
    	}
    };
    
    int main()
    {
    	//注意这里,只能把儿子指针赋值给爸爸,反过来报错
    	CFather* son2 = new CChildren;
    	return 0;
    }
    
    
    展开全文
  • 理解 C++ 虚函数

    2021-03-16 14:47:52
    引言表是 C++ 中一个十分重要的概念,面向对象编程的多态性在 C++ 中的实现全靠表来实现。在聊表之前我们先回顾一下什么事多态性。多态实际上就是让一个父类指针,通过赋予子类对象的地址,可以呈现出多种形态...
  • 在了解虚函数之前先了解下对象模型:对象模型: 在C++中,有两种数据成员(class data members):static 和nonstatic,以及三种类成员函数(class member functions):static、nonstatic和virtual: 说明:采用的是非继承...
  • 版权声明:本文为CSDN博主「Runner_of_nku」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。...显而易见,虚函数表存放在全局数据区. 下面开始试验 class A{ public: ...
  • C++虚函数详解

    2021-05-26 10:25:43
    1.虚函数的使用? 1.1虚函数的定义 在实现c++多态时会用到虚函数虚函数使用的其核心目的是通过基类访问派生类定义的函数。所谓虚函数就是在基类定义一个未实现的函数名,为了提高程序的可读性,建议后代中虚函数...
  • 虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析c++虚函数1.定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数 [1]2.语法:virtual 函数返回类型 函数名(参数表) { 函数体 }3.用途:...
  • C++虚函数虚函数表、多态的深入理解 大家都知道多态发生需要: 要有继承 要有虚函数重写 父类指针指向子类对象 那么c++底层是如何实现多态这个骚操作的呢,接下来我谈谈自己的看法: 首先定义两个类: class ...
  • 目录引用的深入理解继承\组合构造函数谁先调用转换函数malloc的内部实现原理explicitnamespace虚函数指针和虚函数表 引用的深入理解 引用是啥学C++的都知道,那他和指针有何区别?引用不可以更改指向的对象,引用第...
  • 简介虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次:class Father{public:virtual void foo() { cout << "Father::foo() is called"<...
  • 对C++虚函数理解

    2021-06-28 15:45:30
    在基类和派生类中,基类使用virtual关键字定义虚函数,派生类中可以重写基类中的虚函数,运行时根据对象的实际类型来调用相应的函数,如果对象是基类就调用基类的函数,如果对象是派生类就调用派生类的函数。...
  • 经过测试发现,C++类中对普通函数和virtual函数只定义不声明在程序链接时会发生不同的情况。 1.1 类中普通函数只声明不定义 如下图所示,类中普通函数只声明不定义。 程序编译、连接都没有任何问题。 1.2 类中...
  • HOOK虚函数

    千次阅读 2021-02-05 14:50:38
    首先呢,这里会牵扯到虚函数,建议先看看以下博客(前三章就行), c++类成员函数指针 详解虚函数的实现过程之初探虚表(1) 详解虚函数的实现过程之单继承(2) 详解虚函数的实现过程之多重继承(3) 详解虚函数的...
  • 文章目录1、多态与虚函数静态联编动态联编**实现动态联编必须满足以下3个条件:**为什么需要虚函数2、虚函数的访问对象名访问基指针访问引用访问3、纯虚函数与抽象类纯虚函数声明和定义抽象类 1、多态与虚函数 多态...
  • C++多态、虚函数表、动态链接,虚函数指针,RTTI 多态 多态的概念:基类指针指向派生类的地址,通过实现派生类的重写函数实现同一个函数接口不同的功能。多态性在Object Pascal和C++中都是通过虚函数(Virtual ...
  • 虚函数及继承

    2021-03-09 22:53:32
    Derived1和Derived2的结果根据前面关于继承的分析是比较好理解的,不过对于虚继承的方式则有点不一样了,根据结果自己得出的一种关于虚继承的分析,如对Derived3或Derived4定义一个对象d,其里面会出现三个跟虚函数...
  • C++ 虚函数表 vfptr

    2021-01-21 16:37:30
    虚函数带来的好处就是:可以定义一个基类的指针,其指向一个继承类,当通过基类的指针去调用函数时,可以在运行时决定该调用基类的函数还是继承类的函数()。虚函数是实现多态(动态绑定)/接口函数的基础. 可以说: ...
  • 虚函数的作用?

    2021-05-19 07:23:16
    }用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数虚函数必须是基类的非静态成员函数,其访问权限可以是private或protected或public,在基类的类定义中定义虚函数的一般形式:class基类名...
  • 构造函数为和类同名的成员函数,可以多态(含有不同参数的同名函数) 类含有两个成员:数据成员和成员函数 其中构造函数为特殊的成员函数,即创建类的实例时候会直接调用构造函数, 相当于进行了一次构造函数初始化。...
  • 昨天去面试,面试官问道:虚函数有什么作用,我解释了半天也没解释清楚,其实说到底还是理解不够深刻,或者说简直没什么理解,连子类重写父类的普通函数和子类重写父类的虚函数的区别都不知道,真是弱爆了!...
  • 访问基类的私有虚函数 运行结果: B::g A::f B::h 望读到的大佬分析一下 main() 函数里的代码什么意思呀 #include <iostream> using namespace std; class A { virtual void g() { cout << "A::g...
  • 虚函数是一个有助于运行时多态性的概念。在这个博客中,我们将学习javaJava是一种面向对象的编程语言,它支持多态、继承、抽象等概念。这些OOPs概念围绕类、对象和成员函数展开。虚函数是一个有助于运行时多态性的...
  • 虚函数理解

    2020-12-29 11:42:09
    虚函数 理解: 加粗部分表示基类的calcArea 1.定义一个形状基类Shape,类中定义一种方法 double calcArea() 计算形状的面积。派生类有圆形Circle、矩形mRect两个,两个派生类都需继承计算面积的方法,但是两种派生...
  • C++虚函数

    2021-05-18 12:22:29
    title: 理解C++虚函数date: 2018-11-11 15:31:261. 简单介绍C++虚函数是定义在基类中的函数,子类必须对其进行覆盖。在类中声明(无函数体的形式叫做声明)虚函数的格式如下:virtual void display();2. 虚函数的作用...
  • 1.简介虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次:class A{public:virtual void foo() { cout << "A::foo() is called" << ...
  • 下面是对C++的虚函数这玩意儿的理解。一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始)简单地说,那些被virtual关键字修饰的成员函数,就是虚函数虚函数的作用,用专业术语来...
  • java 虚函数

    2021-04-17 05:15:04
    场景:java中的“虚函数”解决方法java中的“虚函数”本帖最后由 sunmoon631 于 2011-05-28 17:58:40 编辑java中是否有“虚函数”,请教高人讲解一下:我的理解是这样C++Java虚函数--------纯虚函数--------抽象方法...
  • C++ 虚函数表 vfptr详解

    2021-04-08 10:51:54
    大家都应该知道C++的精髓是虚函数吧? 虚函数带来的好处就是: 可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时决定该调用基类的函数还是继承类的函数. 虚函数是实现多态(动态...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 85,169
精华内容 34,067
关键字:

虚函数怎么理解