多态

C++多态,虚函数,虚函数表,纯虚函数

旧巷老猫 提交于 2020-02-29 20:55:20
1、多态性 指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。 C++支持两种多态性:编译时多态性,运行时多态性。 a、编译时多态性:通过重载函数实现 ,模板(2次编译) b、运行时多态性:通过虚函数实现。 2、覆盖,隐藏,重载 重载,静态多态,一个类里面 覆盖, 虚函数 ,同参数,同名称,同返回 隐藏 : 1.1 基类非虚函数,子类与父类同名称(可能覆盖一大片父类函数)  1.2 基类非虚函数,派生类声明为virtual ,参数相同,此时virtual关键字失效 2.2 基类虚函数, 派生类不使用virtual, 形参不同,则丢失多态 2.3 基类和派生类都是 虚函数, 形参相同,返回值不同,报错 ////////////////////////// 多态典型应用,抽象工厂模式, /////////////////////////////////////////////////////////// 虚函数表,动态绑定如何实现? 多重继承,一个基类(含虚函数)会有一个虚表指针,继承后,自己的虚函数放在第一个虚表后面。 D:A,B,C; 强转D对象为A,B,C的时候,地址不一样 //////////////////////////////////// 构造函数与析构函数是否能定义为虚函数?能否抛出异常? 构造的时候必须要知道构造的东西结构吧,虚个鸡毛。。

C#学习笔记21-多态之抽象类

…衆ロ難τιáo~ 提交于 2020-02-29 14:01:41
C#学习笔记21-多态之抽象类 抽象类 抽象类特点 抽象类实例 抽象类 在前一篇博客 C#学习笔记20-多态之虚方法 中,我们提到实现多态存在有三种方法,前一篇讲解了虚方法,这一篇继续复习抽象类。当父类中的方法不知道如何去实现时,可以将父类写成抽象类,方法写成抽象类,比如小明打球,小平打球,但是他们如何打球未知,此时就可以写成抽象类来描述 抽象类,顾名思义就是一个抽象的,没有实体(没有具体实现)的类,即抽象类不能被实例化,不能创建对象。 抽象类要实现多态,需要创建抽象方法,需要加上关键字abstract,基本语法如下: public abstract class Animal { public abstract string Name { get ; set ; } public abstract void Bark ( ) ; } 抽象类特点 1)抽象类不允许创建对象,对可以创建子类对象赋值给父类 假设父类为Animal、子类为Dog,则 Animal a1 = new Animal ( ) ; //写法错误,不能创建对象 Animal a2 = new Dog ( ) ; //写法正确 2)抽象类中的成员都必须标记abstract,并且不能有任何实现,抽象类中可以包含实例成员,并且抽象类中实例成员可不被子类实现 3)抽象成员必须在抽象类中,有抽象成员就必须有抽象类 4

《多态》

时光总嘲笑我的痴心妄想 提交于 2020-02-29 09:25:06
【15-1】面向对象-多态-好处&弊端&前提 //描述狗 class Dog extends Animal { public void eat() { System.out.println("吃饭"); } public void lookHome() { System.out.println("看家"); } } //描述猫 class Cat extends Animal { public void eat() { System.out.println("鱼"); } public void catchMice() { System.out.println("抓老鼠"); } } //进行抽取,将共性的功能抽取到父类Animal中。 abstract class Animal { public abstract void eat(); } class DogAndCatTest { public static void main(String[] agrs) { //Dog d = new Dog(); //method(d); Animal a = new Dog(); method(a); //Cat c = new Cat(); method(new Cat()); } /* 发现,每一个动物,都需要为这个动物单独定义一个功能。 让这个动物的对象去做事。

Java中多态应当注意

孤者浪人 提交于 2020-02-29 08:02:57
一、多态的分类: 1、引用多态:父类的引用可以指向本类的对象,父类引用可以指向子类对象,子类引用不能指向父类对象; 2、方法多态:创建本类对象时,调用的方法为本类方法;创建子类对象时,调用的方法为子类重写的方法或者继承的方法; 3、如果子类里有一个独有的方法,并不是从父类中继承过来的,那么就不能通过父类的引用调用子类独有的方法。 二、引用类型转换: 1、向上类型转换(隐式/自动类型转换),是小类型到大类型的转换,不存在风险; 2、向下类型转换(强制类型转换),是大类型到小类型的转换,存在风险; 3、instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题; Dog dog=new Dog(); Animal animal =dog;//向上类型转换 Dog dog2=(Dog)animal; Cat cat =(Cat)animal;//1、编译时不会报错2、实际开辟的内存空间为dog类型,会报错 instanceof运算符,可以判断一个引用是否是某个类型或者是某个类型的子类型,返回一个布尔值; Dog dog=new Dog(); Animal animal =dog;//向上类型转换 Dog dog2=(Dog)animal; if(animal instanceof Cat){ Cat cat =(Cat)animal; }else{ System.out

谈谈多态

时光总嘲笑我的痴心妄想 提交于 2020-02-29 08:02:40
概述 我们都知道面向对象有四个基本特性:抽象、封装、继承、多态。这四个特性,概括起来可以这么理解,抽象、封装、继承是多态的基础,多态是抽象、封装、继承的表现。多态,是Java中非常重要的一个部分,所以今天来谈一下多态(Polymorphism)。 什么是多态 不同类的对象对同一消息作出不同的响应就叫做多态。就像上课铃响了,上体育课的学生跑到操场上站好,上语文课的学生在教室里坐好一样。 多态的作用 简单讲就是解耦。再详细点讲就是,多态是设计模式的基础,不能说所有的设计模式都使用到了多态,但是23种中的很大一部分,都是基于多态的。 多态存在的三个条件 1、有继承关系   2、子类重写父类方法   3、父类引用指向子类对象 补充一下第二点,既然多态存在必须要有“子类重写父类方法”这一条件,那么以下三种类型的方法是没有办法表现出多态特性的(因为不能被重写): 1、static方法,因为被static修饰的方法是属于类的,而不是属于实例的 2、final方法,因为被final修饰的方法无法被子类重写 3、private方法和protected方法,前者是因为被private修饰的方法对子类不可见,后者是因为尽管被protected修饰的方法可以被子类见到,也可以被子类重写,但是它是无法被外部所引用的,一个不能被外部引用的方法,怎么能谈多态呢 多态的分类 1、编译时多态,即方法的重载

理解多态AND理解父类引用指向子类对象

末鹿安然 提交于 2020-02-29 07:45:15
假设现在有一个父类Father,它里面的变量需要占用1M内存.有一个它的子类Son,它里面的变量需要占用0.5M内存. 现在通过代码来看看内存的分配情况: Father f = new Father();//系统将分配1M内存. Son s = new Son();//系统将分配1.5M内存. 因为子类中有一个隐藏的引用super会指向父类实例,所以在实例化子类之前会先实例化一个父类,也就是说会先执行父类的构造函数. 由于s中包含了父类的实例,所以s可以调用父类的方法. Son s1 = s;//s1指向那1.5M的内存.(可以理解为就是:子类引用指向子类对象) Father f1 = (Father)s;//这时f1会指向那1.5M内存中的1M内存,即是说,f1只是指向了s中实例的父类实例对象,所以f1只能调用父类的方法(存储在1M内存中),而不能调用子类的方法(存储在0.5M内存中). Son s2 = (Son)f;//这句代码运行时会报ClassCastException.因为f中只有1M内存,而子类的引用都必须要有1.5M的内存,所以无法转换. Son s3 = (Son)f1;//这句可以通过运行,这时s3指向那1.5M的内存.由于f1是由s转换过来的,所以它是有1.5M的内存的,只是它指向的只有1M内存. 示例: class Father{ void print(){

java多态的内存图解

杀马特。学长 韩版系。学妹 提交于 2020-02-29 07:24:55
版权声明:本文为博主原创文章,未经博主允许不得转载。 图解Java多态内存分配以及多态中成员方法的特点 Person worker = new Worker(); 子类实例对象地址赋值给父类类型引用变量。多态的体现。 多态中成员方法的特点分析: 【子类有,父类没有】编译失败!!! worker.startWork(); 为什么编译不通过呢?提示:找不到符号。 因为引用变量worker是Person类型,在Person类的方法表中查找方法startWork(),找得到吗?找不到,更别提常量池解析了。编译失败。 【子类有,父类有,重写,非静态】调用子类!!! worker.say(); 子类重写父类方法,被重写的方法在子类跟父类的方法表中索引相同。 调用的时候,在父类类型的方法表中查找say方法的索引,然后把索引存到PolDemo类的常量表中(常量池解析,就是用Person类方法表中的索引项来代替常量池中的符号引用)。 因为索引相同,直接拿常量表中say方法的索引去子类方法表中调用say()方法。 所以,此时调用的是被子类重写的方法。见图中的内存分配。 【子类有,父类有,静态】调用当前引用类型变量类型中的方法。 因为静态是属于类的,由实例共享,所以只看当前引用变量所属的类中的静态方法。 多态中(父类引用指向子类对象)成员方法(非静态)有以下特点:

设计模式之开闭原则

假如想象 提交于 2020-02-29 02:47:38
开放封闭原则 (对扩展开放(Open for extension),对修改封闭(Closed for modification))是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所带来的巨大好处,也就是可维护、可扩展、可复用、灵活性好,开发人员应该仅对程序中频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。 接下来以一个计算器类来作为开闭原则案例: # include <iostream> using namespace std ; //开闭原则:对扩展开放,对修改关闭;增加功能时,通过增加代码实现,而不是修改源代码。 //利用面向对象编程的:继承和多态来实现开闭原则 //多态满足条件: //1、有继承关系 //2、子类重写父类中的虚函数 //多态使用: //父类指针或引用指向子类对象 //写一个抽象类,具有纯虚函数的类称为抽象类 class AbstractCaculator { public : virtual int getResult ( ) = 0 ; //纯虚函数 函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。 virtual void setNum ( int a , int b ) = 0 ; } ; //加法计算器 class

从Java角度说起C++虚函数

社会主义新天地 提交于 2020-02-28 22:05:16
多态是面向对象的一大特征,接口的多种不同的实现方式即为多态,简而言之 方法的重载与重写 父类对象的引用指向子类对象的实体 在Java中,如果使用我们刚刚所述的,基类引用指向派生类对象实体,那么调用该引用的函数,实际上会调用派生类的函数,给个例子,相信大家会有更加深刻的体会。 public class Test { public static void main ( String [ ] args ) { A test = new B ( ) ; test . foo ( ) ; } } class A { void foo ( ) { System . out . println ( "This is foo() form A" ) ; } } class B extends A { void foo ( ) { System . out . println ( "This is foo() from B" ) ; } } 这段代码最终输出的结果是 This is foo() from B ,相比而言,C++ 默认就不是这种情况了。 当使用关键字 virtual 声明 foo() 为虚函数的时候,才能更好的实现多态,即,父类对象的引用,指向子类对象的实体,这个父类引用调用虚函数,实际调用的是子类的函数,而非父类。也就是说,Java 默认情况下,使用的就是 C++ 中的虚函数。总之

c++虚函数和虚函数表

故事扮演 提交于 2020-02-28 09:55:14
前言 (1)虚基表与虚函数表是两个完全不同的概念 虚基表用来解决继承的二义性(虚基类可以解决)。 虚函数用来实现泛型编程,运行时多态。 (2)虚函数是在基类普通函数前加virtual关键字,是实现多态的基础 (3)虚函数表其实不用我们管这个编译器会帮我们做好 注:无特别说明本文的虚表均指虚函数表 (一) 什么是虚函数表? 虚函数(Virtual Function)是通过一张虚函数表(VirtualTable)来实现的。简称为V-Table。 虚表(virtual table),编译器为每个拥有虚函数的类都建有一张虚函数表,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数 。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。 C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下) (二)含虚函数的单继承 单继承时,派生类中仅有一个虚函数表。这个虚函数表和基类的虚函数表不是一个表(无论派生类有没有重写基类的虚函数),但是如果派生类没有重写基类的虚函数的话,基类和派生类的虚函数表指向的函数地址都是相同的。 #include