当实例化一个该类的子类对象的时候,如果该类的子类没有定义虚函数,但是却从父类中继承了虚函数,所以在实例化该类子类对象的时候也会产生一个虚函数表,这个虚函数表是子类的虚函数表,但是记录的子类的虚函数地址却是与父类是一样的...原理: 如果父类当中定义了虚析构函数,那么父类的析构函数表当中就会有一个父类的虚析构函数指针,指向的是父类的虚析构函数,子类虚析构函数表当中也会产生一个子类的虚析构函数的入口指针,指向的是子类的虚析构函数...纯虚函数的实现原理 在虚函数原理的基础上,虚函数表中,虚函数的地址是一个有意义的值,如果是纯虚函数就实实在在的写一个0 含有纯虚函数的类被称为抽象类 含有纯虚函数的类被称为抽象类。...哪怕类中只有一个纯虚函数,那么这个类也是一个抽象类,纯虚函数没有函数体,所以抽象类不允许实例化对象,抽象类的子类也可以是一个抽象类。...抽象子类只有把抽象类中所有纯虚函数都做了实现才可以实例化对象。 仅含有纯虚函数的类称为接口类 如果在抽象类中仅含有纯虚函数而不含其他东西,我们称之为接口类。
这样就可以达到预期的结果了 多态中存在的问题 [-:>内存泄漏,一个很严重的问题 例如上面的程序中,如果在圆形的类中定义一个圆心的坐标,并且坐标是在堆中申请的内存,则在mian函数中通过父类指针操作子类对象的成员函数的时候是没有问题的...当实例化一个该类的子类对象的时候,(如果)该类的子类并没有定义虚函数,但是却从父类中继承了虚函数,所以在实例化该类子类对象的时候也会产生一个虚函数表,这个虚函数表是子类的虚函数表,但是记录的子类的虚函数地址却是与父类的是一样的...原理: 如果父类当中定义了虚析构函数,那么父类的虚函数表当中就会有一个父类的虚析构函数的入口指针,指向的是父类的虚析构函数,子类虚函数表当中也会产生一个子类的虚析构函数的入口指针,指向的是子类的虚析构函数...含有纯虚函数的类被称为抽象类 含有纯虚函数的类被称为抽象类,比如上面代码中的类就是一个抽象类,包含一个计算周长的纯虚函数。...哪怕只有一个纯虚函数,那么这个类也是一个抽象类,纯虚函数没有函数体,所以抽象类不允许实例化对象,抽象类的子类也可以是一个抽象类。抽象类子类只有把抽象类当中的所有的纯虚函数都做了实现才可以实例化对象。
如果要其他平台下,部分代码需要改动。比如:如果是x64程序,则需要考虑指针是8bytes问题等等。 1....那我现在这样写: 两个类不动,我把main函数改成这样 注意两个指针都是Person*,一个指向父类对象,一个指向子类对象,这样赋值是没问题的,然后我们运行 大家看这次的析构调用的有没有问题...抽象类 接下来我们再来学一个东西叫做抽象类,先来了解一下它的概念: 在虚函数的后面写上 =0 ,则这个函数为纯虚函数(不需要函数体)。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象。...可以认为如果一个类在现实中没有对应的实体,我们就可以把它定义成一个抽象类。...我们继续: 另外上面还说到抽象类被继承后的子类也不能实例化出对象: 因为这里的子类还是一个抽象类,它也包含纯虚函数,是它继承下来的嘛。
当时学习C++时对多态有一个非常精炼的定义:基类的指针指向不同的派生类,其行为不同。这里行为不同指的是调用同一个虚函数时,会调用不同的派生类函数。...这里我们说形成多态的几个基本条件:1)指针或者引用类型是基类;2)需要指向派生类;3)调用的函数必须是基类重写的函数。...= new Child(); obj.sayHello(); 这个例子也不满足多态,它使用子类的引用指向了子类,这里就是一个正常的类方法调用,它会调用子类的方法 那么多态有什么好处呢?...为什么要进行小转大呢?虽然多态给了我们很大的方便,但是多态最大的问题就是父类引用无法看到子类的成员,也就是无法使用子类中的成员。这个时候如果要使用子类的成员就必须进行小转大的操作。...,但是有抽象方法的一定要是抽象类 接口 接口就是一套公共的规范标准,只要符合标准就能通用,比如说USB接口,只要一个设备使用了USB接口,那么我的电脑不管你的设备是什么,插上就应该能用。
所以,this就是指向当前对象实例的指针,不指向任何其他对象或类。...>上述示例中,在第4行定义了一个静态变量 3.parent关键字 parent是指向父类的指针,一般使用parent来调用父类的构造函数。 抽象类应用的定义如下: abstract class ClassName{ } 抽象类具有以下特点: 1)定义一些方法,子类必须实现父类所有的抽象方法,只有这样,子类才能被实例化,否则子类还是一个抽象类...2)抽象类不能被实例化,它的意义在于被扩展。 3)抽象方法不必实现具体的功能,由子类来完成。...5)如果抽象方法有参数,那么子类的实现也必须有相同的参数个数,必须匹配。
,指针指向的就是子类中父类的那一部分。...如果一个虚函数在接口后面加上=0,则这个虚函数为纯虚函数,纯虚函数所在的类为抽象类,抽象类是不可以被实例化出对象的,如果抽象类被继承,派生类里面天然的就会有纯虚函数,那么派生类也就变成了抽象类,一个类如果连对象都实例化不出来...当一个类里面出现虚函数时,这个类实例化出的对象模型就会发生改变,他的类成员除变量之外,还会多一个虚表指针,这个虚表指针指向一个数组,这个数组里面存放的是类里面虚函数的地址。...需要说清楚的一个概念是,虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是他的指针又存到了虚表中。另外对象中存的不是虚表,存的是虚表指针 3....一般来说,虚基类成员都放在逻辑对象模型中成员的最下面,如果是在内存里面的话,他的位置应该是对象成员中的最高地址处。 11.什么是抽象类?抽象类的作用?
;可以用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数 多态是通过虚函数实现的 多态可以让父类的指针有“多种形态”,这是一种泛型技术(所谓泛型技术,就是试图使用不变的代码来实现可变的算法...如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数 虚函数可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类虚成员函数调用基类指针,则会调用其真正指向的对象的成员函数,而不是基类中定义的成员函数...若不是虚函数,则不管基类指针指向哪个派生类对象,调用时都会调用基类中定义的那个函数 Tip: 虚函数的引入就是为了实现多态的特性,让不同的子类可以有不同的实现方式 ---- 纯虚函数 纯虚函数是一种特殊的虚函数...,则把它声明为纯虚函数,它的实现留给该基类的派生类去做 纯虚函数的作用是为派生类提供一个一致的接口(纯虚函数相当于接口,不能直接实例化,需要派生类来实现函数定义) ---- 虚函数与纯虚函数的区别 1)...如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了 抽象类中,既可以有抽象方法,也可以有具体方法或者叫非抽象方法。
通过之前学习的内容,我们可以了解到,如果类中没有成员变量,只有成员函数,会留一个字节进行占位,因为成员函数在代码段,所以Base1的大小是1吗?...VFptr(全程vftable)是一个指针, 指向虚表,虚表中存的是虚函数的地址。...当子类也有虚函数时,这时子类的虚函数放到第一个继承的父类的虚表中,我们可以从上面代码结果看出。 ---- 再来练习题目: 下列输出的结果是什么?...在有虚函数的类实例中,this指针调用vptr指针,指向的是vtable(虚函数列表),通过虚函数列表找到需要调用的虚函数的地址。...什么是抽象类?抽象类的作用? 抽象类是在虚函数后面写上=0,它强制必须重写子类的虚函数,不写就不可以实例化出对象,另外抽象类体现出了接口继承关系。
,则该类被称为抽象类,抽象类具有以下特点: 抽象类无法实例化对象 抽象类的子类必须重写父类中的纯虚函数,否则也为抽象类 目的 纯虚函数和抽象类的存在是为了更好的契合多态的思想。...关于多态,简而言之就是用父类的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数 问题 纯虚函数的使用也会带来某些问题,由于实际调用时是父类指针指向子类对象,因此如果在子类中开辟了堆区数据,...在析构时父类指针无法指向子类对象,即子类的析构函数不能够正常的被调用,这会带来内存泄漏的问题。...虚析构与纯虚析构 虚析构 虚析构的实现与虚函数一致,只需要在父类的析构函数前面加上virtual关键字即可,只需要将前面代码中的Animal基类改成: class Animal { public:...拥有纯虚析构的类也叫做抽象类,无法实例化对象。
必须是父类的指针或者引用。 因为只有是父类的指针或者引用才可以既能指向父类对象,又能指向子类对象。 简单来说,在传递不同对象时,只有父类的指针或者引用才能接收子类对象或者父类对象。...当子类继承抽象类后不重写虚函数那么子类也是抽象类。所以纯虚函数在某种程度上强制要求子类重写虚函数,因为不重写子类实例不出具体的对象。...一个含有虚函数的类中至少有一个虚函数表指针,一个类所有的虚函数的地址都要放到这个类对象的虚函数表中,虚函数表也叫做虚表。 2.多态如何实现 我们以刚才买票的例子来说明多态是如何实现的。...通过下图我们可以看到,满足多态条件后,底层不再是编译时通过调用对象确定函数的地址,而是运行时到指向的对象的虚函数表中确定对应的虚函数的地址,这样就是实现了父类指针或引用指向父类就调用父类的虚函数,指向子类就调用子类对应的虚函数...答:首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。 9. 虚函数表是在什么阶段生成的,存在哪的?
这种类成为抽象类。 一个抽象类至少具有一个纯虚函数。所谓纯虚函数是指被标明为不具体实现的虚成员函数。...该声明是为派生类而保留的位置。 一个抽象类不能有实例对象,即不能由该类抽象来制造一个对象。 纯虚函数是在基类中为子类保留的一个位置,以便子类用自己的实在函数定义来重载之。...在派生类中允许重载基类的成员函数。如果基类中的函数是虚函数,当使用指针或引用访问对象时,将基于实际运行时指针所指向的对象类型来调用派生类的函数。...因为每个存在虚函数的类都要有一个4字节的指针指向自己的虚函数表,所以每种情况的类a所占的字节数应该是没有什么问题 的,那么类b的字节数怎么算呢?...Range 指针指向,当调用 getRange方法,动态找到相应 Square 和 Circle 实例的getRange方法进行调用。
如果不定义虚析构函数,当删除一个指向派生类对象的指针时,会调用基类的析构函数,派生类的析构函数未被调用,造成内存泄露。...这张表解决了继承、覆盖的问题,保证使用指向子类对象实体的基类指针或引用,能够访问到对象实际的虚函数。...在有虚函数类的实例中,分配了指向这个表的指针的内存,所以,当用父类的指针来操作一个子类对象实体的时候,这张虚函数表就指明了实际所应该被调用的虚函数。...2.纯虚函数与抽象类 既然有了虚函数,那为什么还需要有纯虚函数呢?在Java编程语言中有接口的定义,在C++中虽然没有接口关键字,但是纯虚函数就完成了接口的功能。...所以纯虚函数的声明就是在告诉子类的设计者,“你必须实现这个函数,但我不知道你会怎样实现它”。 值得特别注意的是,由于抽象类至少有一个函数没有实现,所以抽象类无法被实例化,否则编译器会报错。
纯虚函数——虚函数后面加上一个=0 抽象类就是抽象,即**不能实例化出来对象。**派生类继承了也不能实例化出来对象,必要要进行重写,才能实例化出来对象。...虚函数放在虚函数表中,所以的虚函数都放在学函数表中 类中有个虚函数表的指针,指向这个表,在vs2019中,这个指针为vfptr cppclass teacher { public: virtual...这也是为什么说,指向哪里调哪里——父类的指针或引用指向父类调父类,指向子类调子类。...想打印出来它,就要先取到他的地址,然后还要知道它是什么类型? 取到它的地址 直接取对象的地址就可以,虚表的指针都放在对象的第一个位置 什么类型的?...虚表的指针它是一个函数指针数组指针,什么意思呢?——它是一个指针,它指向一个数组,数组的每个元素都是一个函数指针。
多态的构成必须要满足两个条件: 1.必须要通过父类的引用或者指针作为形参来调用 为什么一定要是父类的引用或者指针,对于这个问题《深度探索C++模型》中这样说:“一个pointer或一个reference...如果我定义了一个子类的对象,并将该子类对象赋值给一个父类的指针,当我释放父类的时候只会调用父类的析构函数,也就是说只释放了子类中父类的那一部分资源,而没有释放子类的资源,这就可能会导致内存泄漏。...如果一个类包含纯虚函数,那么这个类就是抽象类。抽象类不能实例化对象,并且如果继承抽象类的子类不对纯虚函数进行重写的话,子类也是一个抽象类无法实例化对象。...但这个类的大小为4字节 这是因为如果一个类中有虚函数,那么该类中会有一个隐藏的指针,该指针指向一个虚函数表。...如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。 虚函数表是在什么阶段生成的,存在哪的?
如果说,抽象类无法实例化对象,那就无法使用对象方法了嘛。...那我现在有一个抽象类的对象,我要调用接口,调用哪个? ---- Q5:基类的析构函数为什么要定义成虚函数?...vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,因为它是类的一个成员,并且vptr指向保存虚函数地址的vtable.对于静态成员函数,它没有this指针,所以无法访问vptr...2、虚函数表类似一个数组,类对象中存储vptr指针,指向虚函数表。...多态的函数调用语句被编译成根据基类指针所指向的(或基类引用所引用的)对象中存放的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数的一系列指令。
动态多态使用:父类的指针或引用 指向子类对象 重写:函数返回值类型 函数名 参数列表 完全一致叫重写 如果子类中没有堆区数据,可以不用写虚析构和纯虚析构。...1.虚析构与纯虚析构共性: 解决父类指针释放子类对象不干净问题 都需要有具体的函数实现 2.区别: 如果是纯虚析构,该类属于抽象类,无法实例化 .虚析构语法: virtual ~类名(){}...指向子类对象发生多态 */ class base { public: //纯虚数 // 子类的内容会覆盖父类,所以父类中函数没有意义了 //类中只要有一个纯虚函数就称为抽象类 virtual...抽象类只能作为基类派生出的新子类,而不能在程序中被实例化(不能声明抽象类的对象),但是可以指向抽象类的指针。...它是实现抽象类和多态性的重要机制之一。 如果某个函数不是抽象类中的成员函数,不能用基类指针调用。
协变(基类与派生类虚函数返回值类型不同) 三同中,返回值可以不同,但是要求返回值必须是一个父子类关系的指针或者引用。...抽象类 在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。...接着是虚表的存在,又称虚函数表,虚函数表本质上是一个函数指针数组,存放的是类中虚函数的地址。因此,指向虚函数表的是虚表指针,在32位平台下,指针的大小是4,因此一共是12个字节。...在调用重写的函数的时候,如果指向的是派生类对象,那么就必须从这个派生类的虚表中拿到这个虚函数的地址。 ②为什么要基类对象的指针或引用去调用虚函数: 首先,虚函数必须写在基类中。...其次,基类指针或引用派生类对象的时候,在切片后,指向的是派生类对象中属于基类成员的那一部分,但总体来说依然是指向派生类的,当需要调用重写的虚函数的时候,就会去基类成员那一部分中找接口,再去派生类中找定义
修饰,此时仍然能构成多态(注意三同,需要构成重写) 父子类中的虚函数返回值可以不相同,但此时需要返回对应的父类指针或子类指针,确保构成多态,这一现象称为 协变(了解) 例外一:子类虚函数没有使用 virtual...,如果是虚函数且三同,则为重写;若不是虚函数且函数名相同,则为重定义 注:在类中,仅仅是函数名相关(未构成重写的情况下),就能触发 重定义(隐藏) ---- 3、抽象类 什么是抽象?...当然不是,抽象类是一种极其特殊的类:不允许实例化对象 什么年代了还下传统围棋~ 3.1、定义与特点 如何实现一个抽象类:在虚函数之后加上 =0,此时虚函数升级为 纯虚函数 纯虚函数也可以与普通虚函数构成重写...答案是 4,当前是 32 位平台下,如果是在 64 位平台,大小会变为 8 大小随平台而变的只能是指针了,因此可以推测当前类中藏着一个 虚表指针 就是依靠这个 虚表指针+虚表 实现了多态 4.1、虚表与虚表指针...( ) A:一个类只能有一张虚表 B:基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表 C:虚表是在运行期间动态生成的 D:一个类的不同对象共享该类的虚表 4.下面程序输出结果是什么
领取专属 10元无门槛券
手把手带您无忧上云