base3,因为eye是个普通函数,在编译阶段就确定好是被谁调用,所以他只认哪个指针指向自己,这里是Animal指针指向,所以他就调用Animal里面的,普通函数是父类为子类提供的“强制实现”,也就是只要是父类指针调用普通函数...,那就是父类的普通函数 而虚函数的作用,主要是为了让父类指针可以调用子类的函数,这种是在运行时才决定调用哪个函数 1、虚函数: C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现...子类可以重写父类的虚函数实现子类的特殊化。 2、纯虚函数: C++中包含纯虚函数的类,被称为是“抽象类”。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。 ...3、普通函数: 普通函数是静态编译的,没有运行时多态,只会根据指针或引用的“字面值”类对象,调用自己的普通函数。 普通函数是父类为子类提供的“强制实现”。 ...因此,在继承关系中,子类不应该重写父类的普通函数,因为函数的调用至于类对象的字面值有关。 参考链接
Person对象买票全价,Student对象买票半价。 那么在继承中,需要以下条件才能构成多态: ①被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写/覆盖。...②必须通过基类的指针或引用调用虚函数。...反思构成多态的条件 通过分析,我们可以好好反思一下构成多态的条件,为什么要虚函数重写,为什么要基类对象的指针或引用调用虚函数。 ①为什么虚函数覆盖/重写: 因为要对派生类的虚表进行覆盖。...在调用重写的函数的时候,如果指向的是派生类对象,那么就必须从这个派生类的虚表中拿到这个虚函数的地址。 ②为什么要基类对象的指针或引用去调用虚函数: 首先,虚函数必须写在基类中。...其次,基类指针或引用派生类对象的时候,在切片后,指向的是派生类对象中属于基类成员的那一部分,但总体来说依然是指向派生类的,当需要调用重写的虚函数的时候,就会去基类成员那一部分中找接口,再去派生类中找定义
那么在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 1....注意: 重写的是实现,即函数体里面的类容,派生类的函数(包括函数名,参数类型:包括缺省值,返回值)都是直接用的基类的,这也解释了为什么派生类的虚函数可以不加virtual(但是函数名,参数类型,返回值要与基类一样...即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时 析构函数的重写(基类与派生类析构函数的名字不同) 如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加...,调用具体的函数,也称为动态多态 多态的条件: 不用派生类(子类)的指针或引用原因:当用子类的指针或引用作为函数形参数时,如果是基类对象作为实参,则无法完成参数的正确传递(子类对象可赋给父类对象,这是由于子类的类容...虚函数覆盖:派生类中重写的虚函数会覆盖派生类对象虚表中的基类继承的函数指针,未重写的基类的虚函数依次存储在该派生类对象的虚表中,这样派生类对象的虚表中就同时存在基类与派生类的函数指针,在用基类对象指针或引用调用的时候通过
比如Student类继承了Person类。Person对象买票全价,Student对象买票半价。那么在继承中要构成多态还有两个条件1. 必须通过基类的指针或者引用调用虚函数 2....被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。...为了方便使用,人们想出用一个调用形式,调用基类和派生类的同名函数,通过指针分别调用这些同名的函数。允许在派生类中重新定义和基类同名的函数,并可以通过基类指针或引用来访问积累和派生类中的同名函数。...协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。
切片: 我们都知道,多态的的条件是虚函数的重写和必须通过基类的指针或者引用调用虚函数。。那么为什么一定是需要基类的指针或引用呢? 先来看看不用指针或引用,也就是使用基类对象来调用虚函数。...因此,简单的总结就是:派生类对象赋值给基类对象,切片会把派生类中包含的基类成员变量的值拷贝过去,但是派生类的虚表不会给拷贝过去,则函数中这个基类对象的虚表是基类的,所以无法实现多态。...而指针或者引用是直接指向派生类对象,不会进行拷贝赋值,这样虚函数表是派生类的虚函数表,故能实现多态。 5.inline函数可以是虚函数吗?...因为有时候我们难免会用基类指针或引用指向派生类对象,基类的析构函数是虚函数的话,可以准确地调用派生类的析构函数。 8.对象访问普通函数快还是虚函数更快? 首先如果是普通对象,是一样快的。...如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。 9.什么是抽象类?抽象类的作用? 一个类中的虚函数如果是纯虚函数的话,那么这个类便是抽象类。
2.1.1 为什么需要基类指针或引用 在C++中,如果直接使用派生类对象,即使它重写了基类的虚函数,编译器仍然会使用静态绑定,即在编译时确定调用的函数版本。...动态绑定:在main函数中,通过基类引用和指针来调用派生类的sound方法,输出的是实际派生类的结果。...虚函数允许基类的指针或引用在运行时根据对象的实际类型调用派生类的重写方法,而不仅仅局限于基类的实现。这种机制在面向对象设计中非常重要,尤其在抽象接口、工厂模式等设计模式中广泛应用。...虚函数必须通过基类指针或引用来调用,才能触发多态行为。 2.2.2 如何定义虚函数 虚函数在基类中声明时加上 virtual 关键字即可。...基类指针或引用:虚函数的多态性只能通过基类的指针或引用来调用,如果直接使用派生类对象,则编译时会使用静态绑定。
运行时多态: 通过虚函数和继承实现,是在运行阶段确定函数调用。运行时多态允许通过基类指针或引用来调用派生类的函数,实现了动态绑定。...通过基类指针或引用调用虚函数时,将根据对象的实际类型调用相应的派生类函数 从上面这段话我们知道在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数...基类对象的指针 / 引用调用虚函数的原理是什么?...这种动态绑定的过程使得程序在运行时能够根据对象的实际类型来调用正确的虚函数,实现了多态性 为什么多态必须要用基类的指针 / 引用来调用虚函数,而用基类对象调用却不行 当派生类对象赋值给基类对象时...多态必须使用基类的指针/引用来调用虚函数的原因主要是因为基类指针/引用可以在运行时指向派生类对象,而且能正确地调用派生类的虚函数。
二、多态的定义和实现 1.多态构成条件 在继承中要形成多态还有两个条件: 调用时必须要通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须含有对基类的虚函数的重写 这里我们插入一个概念...,你传递的是父类就调用父类的函数,传递的是子类就调用子类的函数, 在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性...虚函数重写的两个例外: 2.1协变 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。 注意这里的包含,只要类里面有一个有纯虚函数,就是抽象类,就无法实例化对象,间接强制派生类重写。...普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。
必须通过基类的指针或者引用 调用虚函数 2....被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行 重写 虚函数 虚函数:即被 virtual 修饰的类成员函数称为虚函数。...派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。...即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...这样就实现出了不同对象去完成同一行为时,展现出不同的形态。 4. 反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用虚函数。反思一下为什么? 5.
在派生类中实现的函数可以覆盖基类中的同名函数,而且会在运行时的对象类型上调用合适的函数。通过将基类指针或引用指向派生类对象,可以实现动态多态性。 (2)模板(template)。...父类指针/引用指向子类对象:必须是父类的指针或者引用调用虚函数,才能进行多态操作。 二、何为虚函数? C++中的虚函数是一种特殊的成员函数,用于在继承关系中实现多态性。...在父类中通过关键字virtual声明的函数为虚函数,子类可以覆盖并重新实现(重写)该函数。当通过父类的指针或引用调用虚函数时,实际调用的是子类中的实现,而不是父类的实现。这样就实现了多态....虚函数的特殊情况: 斜变 派生类重写基类虚函数时,与基类虚函数返回值类型不同。 基类虚函数返回基类对象的指针或者引用. 派生类虚函数返回派生类对象的指针或者引用时....为什么析构函数要实现多态? 因为析构函数实现多态了以后,才能实现在析构基类和派生类时,各自调用自己的析构函数,防止内存泄漏!
函数模板的使用 动态多态 在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据所指对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,...必须是虚函数(派生类一定要重写基类中的虚函数) ---- Q2:什么是纯虚函数,与虚函数的区别 1、定义一个函数为虚函数,不代表函数为不被实现的函数。...那我现在有一个抽象类的对象,我要调用接口,调用哪个? ---- Q5:基类的析构函数为什么要定义成虚函数?...只有在基类析构函数定义为虚函数时,调用操作符delete销毁指向对象的基类指针时,才能准确调用派生类的析构函数(从该级向上按序调用虚函数),才能准确销毁数据。...多态的函数调用语句被编译成根据基类指针所指向的(或基类引用所引用的)对象中存放的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数的一系列指令。
在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 举个栗子: 2.2 What is 虚函数?...Person类, 并且student类重写了基类的函数, 构成多态, 当不同对象传递给基类的指针或者引用时, 基类的指针或者引用调用虚函数呈现出不同的状态. 2.4 协变 协变(基类与派生类虚函数返回值类型不同...即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...这样就实现出了不同对象去完成同一行为时,展现出不同的形态。 反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用虚函数。反思一下为什么?...以下关于纯虚函数的说法,正确的是(A ) A:声明纯虚函数的类不能实例化对象 B:声明纯虚函数的类是虚基类 C:子类必须实现基类的纯虚函数 D:纯虚函数必须是空函数 5.
那么在继承中要构成多态还有两个条件: 1.必须通过基类的指针或者引用调用虚函数 2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数重写 #include using namespace...即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...三个概念的对比: 重载:1.两个函数再同一作用域 2.函数名/参数相同 重写(覆盖):1.两个函数分别再基类和派生类的作用域 2.函数名/参数/返回值都必须相同(协变除外) 3.两个函数必须是虚函数...2.基类a对象和派生类b对象虚表是不一样的,这里我们发现f1()完成了重写,所以b的虚表中存的是重写的A::f1(),所以虚函数的重写也叫做覆盖,覆盖就是指虚表中虚函数的覆盖。...这样就实现出了不同对象去完成同一行为时,展现出不同的形态。 反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调 用虚函数。反思一下为什么? 完
Adult 对象买票全价,Student对象优惠买票。 实现多态还有 两个必须 重要条件: 必须是基类的指针或者引⽤调⽤虚函数 被调⽤的函数必须是虚函数,并且完成了虚函数重写/覆盖。...说明:要实现多态效果,第⼀必须是基类的指针或引⽤,因为只有基类的指针或引⽤才能既指向基类 对象⼜指向派⽣类对象;第⼆派⽣类必须对基类的虚函数完成重写/覆盖,重写或者覆盖了,基类和派 ⽣类之间才能有不同的函数...void Ticket(Adult* pa) //基类的指针 { pa->BuyTicket(); } 前面说过,多态的第一个条件,必须是基类的指针或者引⽤调⽤,这里的pa满足;第二个条件,被调用函数必须是虚函数而且进行了虚函数的重写...对实例进一步解释 1.为什么一定是基类的指针或引用?...在继承中我们说过派生类和基类的切片/切割问题,参数类型是基类可以保证实参传基类的对象也可以,传派生类的对象也可以。如果是派生类的指针或引用,基类对象根本传不过去。
那要想实现多态,必须满足两个条件 2.2.1 条件1:虚函数的重写 第一个条件: 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 那什么是虚函数的重写呢?...2.2.2 条件2:基类的指针或者引用调用虚函数 第二个条件: 必须通过基类的指针或者引用调用虚函数 我们先学语法,后面会给大家讲原理。...另外还可以是基类的指针去调用: 我们说必须是基类的指针或者引用去调用虚函数,那就意味着用基类的对象是不行的: 虽然没有报错,但是并没有实现多态。...但是是有要求的: 基类虚函数必须返回基类对象的指针或引用,派生类虚函数必须返回派生类对象的指针或引用,我们把这种情况称为协变。...那第二个条件:必须是基类的指针或引用去调用,满足吗? ,其实也是满足的。
虚函数 当我们使用基类的引用或者指针调用一个虚成员函数的时候会发生动态绑定,直到运行时我们才能知道到底调用了哪个版本,所以所有的虚函数都必须有定义。...即如果我们通过基类的引用或者指针调用函数,则使用基类中定义的默认是残,即使实际运行的是派生类中的函数版本也是如此。 如果虚函数使用哪个默认实参,那么基类和派生类中定义的默认实参最好一致。 5....,则编译器产生的代码将在运行时确定到底运行虚函数的哪个版本,依据是对象的动态类型 如果mem不是虚函数或者我们是通过对象(非引用或者指针)进行调用,则编译器将产生一个常规函数调用 5....虚函数与作用域 从名字查找先于类型检查我们可以得知为什么基类和派生类中的虚函数为什么必须有相同的形参列表了。...假如基类和派生类的虚函数接收的实参不同,那么我们就无法通过基类的引用或者指针调用派生类的虚函数了。
,其解析过程发生在编译时而非运行时 派生类可以不覆盖(重写)它继承的虚函数 重写(覆盖)的概念与规则 派生类重写(覆盖)基类中的函数,其中函数名,参数列表,返回值类型都必须一致,并且重写(覆盖)的函数是...virtual函数 虚函数在子类和父类中的访问权限可以不同 相关规则: ①如果虚函数的返回值类型是基本数据类型:返回值类型必须相同 ②如果虚函数的返回值类型是类本身的指针或引用:返回值类型可以不同,但派生类的返回值类型小于基类返回值类型...{}; virtual B& func() {}; //重写了基类的虚函数 }; 二、为什么要设计虚函数 我们知道派生类会拥有基类定义的函数,但是对于某些函数,我们希望派生类各自定义适合于自己版本的函数...fun1时,必须传入a和b }; 七、动态绑定 概念:当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定到该调用哪个版本的函数(根据该指针所绑定的对象) 必须清楚动态绑定只有当我们通过指针或引用调用...“虚函数”时才会发生,如果通过对象进行的函数调用,那么在编译阶段就确定该调用哪个版本的函数了(见下面的演示案例) 当然,如果派生类没有重写基类的虚函数,那么通过基类指针指向于派生类时,调用虚函数还是调用的基类的虚函数
1.1、实现多态还有两个必须重要条件: 必须指针或者引用调用虚函数 被调用的函数必须是虚函数。...说明:要实现多态效果,第⼀必须是基类的指针或引用,因为只有基类的指针或引用才能既指向派生类对象;第二派生类必须对基类的虚函数重写/覆盖,重写或者覆盖了,派生类才能有不同的函数,多态的不同形态效果才能达到...即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派⽣类对象的指针或者引用时,称为协变。协变的实际意义并不⼤,所以了解⼀下即可。...⼤家要结合类似下面的样例才能明白,为什么基类中的析构函数建议设计为虚函数。...通过下图我们可以看到,满足多态条件后,底层不再是编译时通过调用对象确定函数的地址,而是运行时到指向的对象的虚表中确定对应的虚函数的地址,这样就实现了指针或引用指向基类就调用基类的虚函数,指向派生类就调用派生类对应的虚函数
多态的定义和实现 1.多态的构成条件 必须通过 基类的指针或者引用 调用虚函数 被调用的函数 必须是虚函数,且派生类必须对基类的虚函数进行重写 那么问题来啦,什么是虚函数?重写又是什么?请看下面!...即基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类对象的指针或引用时,称为协变。...函数名、返回值类型、参数都必须相同(协变除外) 两个函数都必须是虚函数 对于 隐藏(重定义) 的条件: 两个函数分别在基类和派生类的作用域 函数名相同即可 两个基类和派生类的同名函数不构成重写的话则构成隐藏...派生类继承后也不能实例化出对象,只有派生类重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。...void Func(A& a) //为什么这里不能是父类对象?而一定要是父类的引用或指针呢?
被调用的函数必须是虚函数,且派生类必须对基类的虚函数重写(实现) 必须是基类的指针或引用调用虚函数 多态是在不同继承关系的类对象去调用同一个函数,产生了不同的行为。...虚函数重写的两个例外: 协变(了解) 派生类重写基类虚函数时,与基类虚函数的返回类型不同。即基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类对象的指针或引用时,称为协变。...多态删除:在使用多态时(即基类指针指向派生类对象),如果通过基类指针删除派生类对象,并且基类析构函数没有被声明为虚函数,那么只会调用基类的析构函数,而不会调用派生类的析构函数。...2.2 多态的原理 这里我们再简单总结一下多态的原理: 多态是不同对象去完成同一个行为,展现出不同的形态 多态有两个必须条件:虚函数覆盖和对象的指针或引用调用虚函数 对象切片: 需要注意的是,多态性仅适用于通过基类指针或引用来调用虚函数...当一个函数在基类中被声明为虚函数后,派生类可以重写这个函数,创建自己的实现。如果通过基类的指针或引用调用这个函数,那么实际调用的版本将根据对象的实际类型(运行时的类型)来确定。
领取专属 10元无门槛券
手把手带您无忧上云