多态

C++对象模型学习

北城余情 提交于 2020-04-06 13:43:51
更新记录 时间 更新记录 2020年4月6日 初稿 背景 自从转入iOS,学习到iOS的方法调度,runTime的知识,了解了一下iOS的对象模型。 为了对iOS有更深入的了解,也对之前所学习的C++做一些补充,特此先学习一下C++的对象模型(说来也惭愧,windows开发一年半,没有看到C++对象模型相关的书或者网文) 三种对象模型 简单对象模型 所有的成员变量、成员函数都作为对象在内存中的一部分 简单、粗暴 缺点:占用内存大,以生成对象个数线性递增。 函数是所有对象共用,其实没有必要每个对象都记录,可以统一到某个地方。 表格驱动模型 区分数据成员和函数成员 对象只存放数据表指针和函数表指针,所以对象内存固定 针对于简单对象模型,表格驱动模型把数据成员列表作为每个对象独有的内存数据,而成员函数表则作为所有对象共享的内存数据,即可以解决简单对象模型“占用内存多”的问题 缺点 无法支持多态(确切地说,支持起来就比较复杂或者麻烦) 查找数据成员时,较第一种方案多了一次寻址。而且每个对象都多了一个表格指针,内存升高了。 (要知道C++可是非常重视性能的,每次查找数据成员都要多一次寻址,而数据成员可能用的很多) 调用成员函数时,较第一种方案多了一次寻址。 同上,C++的成员函数也可能调用的很频繁 当前的C++对象模型 对象第一个字节(32位系统下)存储虚函数表指针(如继承树上有虚函数)

Java三大特性之多态

橙三吉。 提交于 2020-04-06 02:32:27
一、概念 所谓多态,就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 通俗来说,就是用父类来声明对象,而用子类来new对象。这依赖于“向上转型”,即由于子类是由父类继承而来的,所以new出的子类对象可以自动向上转型为父类。 当然这样的向上转型也有相应的缺陷,就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了。 二、实现 1.实现条件 继承:在多态中必须存在有继承关系的子类和父类。 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。 2.实现形式 继承 接口 3.多态的继承原则 当超类对象引用变量引用子类对象时

《java编程思想》多态与接口

我们两清 提交于 2020-04-05 18:56:10
向上转型   定义:把某个对象的引用视为对其基类类型的引用的做法被称为向上转型 方法调用绑定   将一个方法调用同一个方法主体关联起来被称作绑定。   前期绑定:程序执行前进行的绑定叫做前期绑定,前期绑定也是java中默认的绑定方式   后期绑定(动态绑定或运行时绑定):在运行时根据对象的类型进行绑定。在java中除了static方法和final方法之外,其他所有的方法都是后期绑定,也就是说,通常情况下,我们不用判断是否应该进行后期绑定,它会自动发生。 构造器和多态   构造器调用顺序:   (1) 调用基类构造器,此步骤会不断反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,一直到最低层的导出类   (2) 按声明顺序调用成员的初始化方法。   (3) 调用导出类构造器的主体       父类(静态变量、静态初始化块)>子类(静态变量、静态初始化块)>   父类(变量、初始化块)>父类构造器>子类(变量、初始化块)>子类构造器。(变量和初始化块按定义顺序初始化)     构造器内部的多态方法的行为   构造器调用的层次结构带来一个有趣的两难问题,如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,会发生什么情况呢?众所周知,在一般的方法内部,动态绑定的调用是在运行时才决定的,因为对象无法知道它是属于方法所在的类,还是属于那个类的导出类

Java面向对象三大特征

一曲冷凌霜 提交于 2020-04-04 17:52:22
封装 封装的好处 1、封装之后,复杂的事物被“包起来”了。复杂性封装,对外提供简单的操作入口。比如照相机,照相机内部结构、实现原理都很复杂,然而对于使用者就很简单。 2、封装之后才会形成真正的“对象”,真正的“独立体”。 3、封装意味着以后的程序可以重复使用,并且这个事物应该适应性比较强,在任何场合都适用。 4、封装之后,对于事物本身,提高了安全性【安全级别高】。 封装的步骤 1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。(例子:private int age,age属性私有化,在外部程序不能直接访问) 2、对外提供简单的操作入口,也就是说以后外部程序要想访问age属性,必须通过这些简单的入口进行访问。(属性的访问形式:读取属性的值(get);修改属性的值(set)。) 3、对外提供两个公开的方法,分别是set方法和get方法:想修改属性,调用set方法;想读取属性,调用get方法。 4、set方法的命名规范: public void set+属性名首字母大写(形参){ 安全控制; Java代码; } 例子: public void setAge(int a){ if(a<0 || a>150){ return; } age = a; } get方法的命名规范: public 参数类型 get+属性名首字母大写(){

Java-继承,多态练习0922-03

自古美人都是妖i 提交于 2020-04-03 22:14:34
编写一个Java应用程序,该程序包括3个类:Monkey类、People类和主类 E。要求: (1) Monkey类中有个构造方法:Monkey (String s),并且有个public void speak() 方法,在speak方法中输出“咿咿呀呀......”的信息。 (2)People类是Monkey类的子类,在People类中重写方法speak(),在speak方法 中输出“小样的,不错嘛!会说话了!”的信息。 (3)在People类中新增方法void think(),在think方法中输出“别说话!认真思考!” 的信息。 (4)在主类E的main方法中创建Monkey与People类的对象类测试这2个类的功 能。 父类: package com.lianxi2; public class Monkey { private String s; public String getS() { return s; } public void setS(String s) { this.s = s; } public Monkey(String s) { this.s=s; } public Monkey() { super(); } public void speak() { System.out.println("咿咿呀呀......"); } } 子类: package

多态

痞子三分冷 提交于 2020-04-02 05:51:35
——“面向对象的三大特性是什么?” ——“封装、继承、多态。” 这大概是最容易回答的面试题了。但是,封装、继承、多态到底是什么?它们在面向对象中起到了什么样的作用呢? 多态 多态(Polymorphic)其实也是一个顾名思义的词:“多态”就是一种事物的“多”种形“态”。 “多态”这个概念在面向对象中同样有多种形态:类的多态、方法的多态、以及实例的多态。 类的多态 类的多态最常见、也最好理解。子类继承了父类(包括实现某个接口)后,父类就有了多种形态:它既可以是父类本身,也可以是它的子类A,还可以是它的子类B、甚至可以是子类A的子类A1……在《 继承 》一文中,这种多态的例子比比皆是,这里就不赘述了。 方法的多态 绝大多数情况下,子类继承了父类之后都会重写父类的方法实现。这时,同一个方法就有了多种不同的实现,这就是一种方法的多态。当然,除了重写之外,还有一种方法的多态叫做“重载”,即通过修改方法的参数列表(参数类型、参数个数等)来为同一个方法提供多种实现。 不过我个人不太喜欢重载,也不太愿意把归入多态之中。Java以方法名+参数列表作为一个方法的“签名”,而重载修改了参数列表,也就修改了方法签名。这时,重载后的这些方法还能称为“同一个方法”的不同实现吗?此外,Java会在编译期就确定使用哪个重载方法,但只有到了运行时才能知道使用的是哪个类重写的方法。也就是说,重载并不具备多态所应有的

c++为什么要面向对象?

夙愿已清 提交于 2020-04-01 07:58:13
前言   c和c++的区别是什么?不可置否,最重要的就是c++的编程思想是面向对象,而c的编程思想是面向过程,这是它们的本质区别,如果你在使用c++编程时使用的还是面向过程的编程思想,那么还不如使用c,因为这样的做法已经丢掉了c++的思想精髓。在学习一门语言时,最重要的是学习它的设计思想,因为语法都是大同小异的,很快便可以掌握。那么面向过程和面向对象编程的发展历史如何,区别是什么,各自的优缺点是什么,且听我一一道来。    一、“自顶向下,逐步求精”的面向过程程序设计    面向过程程序设计的思想即这样的一种解决思路 - 提出问题,分析问题的处理流程,将大问题分解为小问题,如果小问题比较复杂,就继续划分小问题为更小的问题,然后通过小模块一一解决小问题,最后再根据整个业务流程将这些小问题串在一起(调用函数),这样就达到了解决所有问题的目的,如下:   于是,这样从问题出发,自顶向下、逐步求精的开发思想我们称之为“面向过程程序设计思想”,因为它主要是解决问题中的一个个过程。这种思想也是最早的编程语言的思想,因为它比较符合我们解决问题的方法,其他语言比如早期的Fortran、JavaScript等都是如此。它的优点如下: 优点1:程序结构简单 - 仅由三种基本结构组成   面向过程编程的思想在程序实现上只需要三种控制结构,即顺序、选择、循环。通过这三种基本结构,我们就可以解决任何问题

Python-Day6 面向对象

穿精又带淫゛_ 提交于 2020-04-01 07:57:09
一、面向过程 VS 面向对象 编程范式 编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 ,一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。两种最重要的编程范式分别是面向过程编程和面向对象编程。 面向过程编程(Procedural Programming) Procedural programming uses a list of instructions to tell the computer what to do step-by-step. 根据业务逻辑从上到下写垒代码。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。 这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,如果程序开头你设置了一个变量值为1,但如果其它子过程依赖这个值为1的变量才能正常运行,那如果你改了这个变量

C++学习笔记45:多态性

安稳与你 提交于 2020-03-30 21:23:37
运算符重载 运算符是针对新类型数据的实际需要,对原有运算符进行适当的改造 1.比如使复数类的对象可以使用+运算符实现加法; 2.比如使时钟类的对象可以用++运算符实现时间增加1秒; 注意:可以重载为类的非静态成员函数、非成员函数 重载为类成员的运算符函数定义形式: 函数类型 operator 运算符(形参) {   ... } //参数个数=原操作数个数减1,(后置++,--除外) 如何重载运算符为非成员函数? 有些运算符不能重载为成员函数,例如二元运算符的左操作数不是对象,或者不能由我们重载运算符的对象; 备注:如果在重载运算符函数中要操作某类对象的私有成员,可以将此函数声明为该类的友元; 后置单目运算符的重载函数,形参列表中要增加一个int,但不必写形参名: 例如: 表达式 oprd B 等同于operator B(oprd,0) 虚函数: 通过虚函数实现运行时多态性,实现动态绑定; 虚函数必须是非静态的成员函数(属于对象的,而不是类的),虚函数经过派生后就可以实现运行过程中的多态; 注释: 一般的成员函数可以是虚函数; 构造函数不能是虚函数; 析构函数可以是虚函数; 虚函数一般不声明为内联函数,因为内联函数的处理是静态的; 虚析构函数 可能通过基类指针删除派生类的对象;如果需要通过基类指针调用对象的析构函数,就需要让基类的析构函数成为虚函数; 虚表与动态绑定 虚表

C++学习笔记-多态

守給你的承諾、 提交于 2020-03-30 17:23:37
多态作为面向对象的重要概念,在如何一门面向对象编程语言中都有着举足轻重的作用,学习多态,有助于更好地理多态的行为 多态性(Polymorphism)是指一个名字,多种语义;或界面相同,多种实现。 重载函数是多态性的一种简单形式。 虚函数允许函数调用与函数体的联系在运行时才进行,称为动态联编 静态联编 联编是指一个程序模块、代码之间互相关联的过程 静态联编,是程序的匹配、连接在编译阶段实现,也称为早期匹配。重载函数使用静态联编 动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编。switch语句和if语句是动态联编的例子 普通成员函数重载可表达为两种形式: 在一个类说明中重载 Show(int , char); Show(char * , float); 基类的成员函数在派生类重载。有 3 种编译区分方法: 根据参数的特征加以区分 Show(int , char); Show(char * , float); 使用 :: 加以区分 A :: Show(); B :: Show(); 根据类对象加以区分 //这其实是通过this指针区分 Aobj.Show();//调用 A :: Show() Bobj.Show();//调用 B :: Show() 类指针的关系 基类指针和派生类指针与基类对象和派生类对象4种可能匹配: 直接用基类指针引用基类对象 直接用派生类指针引用派生类对象