面向对象思想


前言:整理这份资料的目的是为了帮助我的同学能够更直观的理解面向对象的 编程。让后来者能够少走一些弯路。但其中不免有许多漏洞及错误,也还请前辈提 出宝贵的更改意见,毕竟交流会让我们不断的进步。 技术是日新月异的,他不会等待你的成长。技术要拿出来于别人交流,自己学 是自己主观意识上的理解,有对有错!交流会让进步变得更快。我认为如果计算机 的体系结构不发生革命性的变化,我们现在所应用的程序语言也就百变不离奇踪了! 学编程学的是什么?思想!精通一门编程语言(最好是面向对象的语言)后再去搞 其他的编程语言,你会发现过程是如此的行云流水!为什么?你已经把编程的思想 掌握了,再去学其他的,无非是学习一种新的语法格式了。 我在这里并不是和你讨论怎么去用 C++或 JAVA,也不是和你讨论怎么去学他 “们,我要和你讨论的是怎么去理解面向对象。其中主要会涉及到 类、对象、继承、 ”属性、方法、静态、重载、隐藏、重构、声明、定义、初始化、赋值等 其中有许 多相关技术我只会一代而过,让你有一种到此一游的意味我就达到目的了,而更详 细的技术内幕,就请参考其他相关书籍而深入研究吧!因为我只是在和你探讨如何 去更好的理解面向对象! 如何去提高效率?重复使用资源,把别人的东西拿来就用。这是很不错的主意! 而对于你来说,最大的资源就是信心以及积极性!好,打起精神来,让我们一同到 面向对象的编程中去寻幽访胜吧! 注:文章中所有程序实例我都使用 JAVA 写的,当然在 C++中也就大同小异了了, 不同的地方我会指出! 注:文章中的正文文字用黑色,说明文字用蓝色,强调文字用橙色,批改文字用 红色! 正文: 1.基本概念: 1.1 类与对象的初探 要我说,无论是面向过程的语言也好,面向对象的语言也罢,我首先要给他讲 的都是类和对象!--------“ ”这个世界是由什么组成的? 这个问题如果让不同的人 “来回答会得到不同的答案。如果是一个化学家,他也许会告诉你 还用问嘛?这个 ”世界是由分子、原子、离子等等的化学物质组成的 。如果是一个画家呢?他也许 “ ” ……会告诉你, 这个世界是由不同的颜色所组成的 。 呵呵,众说纷纭吧!但如果 “让一个分类学家来考虑问题就有趣的多了,他会告诉你 这个世界是由不同类型的 ”物与事所构成的 好!作为面向对象的程序员来说,我们要站在分类学家的角度去 考虑问题!是的,这个世界是由动物、植物等组成的。动物又分为单细胞动物、多 ……细胞动物、哺乳动物等等,哺乳动物又分为人、大象、老虎 就这样的分下去了! “现在,站在抽象的角度,我们给 类”下个定义吧!我的意思是,站在抽象的角 “”度,你回答我 什么是人类? 首先让我们来看看人类所具有的一些特征,这个特征 包括属性(一些参数,数值)以及方法(一些行为,他能干什么!)。每个人都有 身高、体重、年龄、血型等等一些属性。人会劳动、人都会直立行走、人都会用自 己的头脑去创造工具等等这些方法!人之所以能区别于其它类型的动物,是因为每 “个人都具有人这个群体的属性与方法。 人类”只是一个抽象的概念,它仅仅是一个 “概念,它是不存在的实体!但是所有具备 人类”这个群体的属性与方法的对象都叫 “人!这个对象 人”是实际存在的实体!每个人都是人这个群体的一个对象。老虎为 什么不是人?因为它不具备人这个群体的属性与方法,老虎不会直立行走,不会使 用工具等等!所以说老虎不是人! 由此可见-------类描述了一组有相同特性(属性)和相同行为(方法)的对象。 在程序中,类实际上就是数据类型!例如:整数,小数等等。整数也有一组特性和 行为。面向过程的语言与面相对象的语言的区别就在于,面向过程的语言不允许 程序员自己定义数据类型,而只能使用程序中内置的数据类型!而为了模拟真实 世界,为了更好的解决问题,往往我们需要创建解决问题所必需的数据类型! 面向对象编程为我们提供了解决方案。 1.2 内置数据类型与函数: 计算机程序在存储数据时必须跟踪 3 个基本属性为: 1. 信息存储在何处; 2. 存储的值是多少; 3. 存储的信息是什么类型的; 让我们来看看编程语言的内置数据类型都有哪些!(呵呵,这个不大好说,因 为每门语言都有自己独特的数据类型,但这毕竟是少数,比如在 JAVA 中有 byte 类型的数据,而在 C++中就没有,希望你能举一反三!)比如整数”int ”,浮点类 型的数据”float”!字符串”String”,以及数组还有结构体等等。然而在写程序的时 候,根据需要我们会创建一个类型的变量或常量,例如:由于我们需要创建一个整 形的变量 i 为 5,我们就可以这样做,int i = 5;而根据需要我很有可能改变 i 的值, 也就是从新给它赋值,比如让它等与 6,就可以在所需的地方改成 i = 6;由此我们 “”知道,在 值 上可以发生变化的量就叫变量。不会发生变化的量就叫做常量了,在 C++中用 count 关键字来声明,而在 JAVA 中则使用 final 关键字来声明。 由于不同语言的声明格式不一样,这里就不做一一介绍了,详细的内容清查阅相关 书籍! “在这里我们主要讨论一下函数,我们可以把函数想象成一个 实现某种特定功 能的黑匣子”-------“这个功能是由你来设定的,举个例子来说:现在我问你 2+3 ”等于多少 ?我相信你能很快的回答我等于 5。让我们来分析分析这句话包含什么 信息!首先我要把你的大脑想象成是一个黑匣子,我并不知道也没有必要知道你的 大脑是如何工作的(也就是怎么运算的),我关心的只是我传给你的是什么信息? 你对信息做了哪些处理? 以及你返回给我的是什么信息?需要提醒你一下的是每 个方法都会返回一个信息给调用者的,除了构造函数外(稍候我会作详细的介绍)。 我现在需要把自己当作是一名程序员,而你呢?当然就是计算机了!计算即可没有 人那么聪明,它只会按事先约好的特定的格式运行,我想让它具有如上所述的功能, 我就要先定义这个黑匣子!首先我要告诉这个黑匣子会有两个整数值给你(这就是 所谓的参数,是程序员需要给黑匣子的信息),然后就要定义这个黑匣子内部实现 这两个整数相加的运算(这就是黑匣子对数据所做的加工,根据需要,你可以做任 何的加工。)。最后再标注它返回给我一个同样是整型的数值(这是黑匣子返回给 程序员的信息)。一个函数就这样定义完了,让我们来看看书写格式: int addnum(int x,int y){ return x+y; } 具体的含义是这样的: int /*返回值类型*/ addnum /*方法(黑匣子)名称*/ (int x,int y/*传入 的参数*/){ return x+y; /*内部是想方法(实现相加运算,)并用 return 返回给调用 者结果*/ } “首先请注意上明的 return”语句!return 关键字的含义是向调用者返回紧跟在它 后面的信息!就像上面一样,因为我问你,你才会回答我,如果我不问你,你就不 用回答我的!在计算机中也一样,定义好这个函数在哪里调用呢?我只能告诉你, 哪里需要就在哪里调用!当然,你可以根据需要去更改参数、返回值以及内部实现, 具体到如何定义如何调用你只好去参考相关的资料了!在这里我只是给你一个思想! 有时你会遇到这样的问题,我让你记住,我的年龄是 20 岁!从字面上理解,你 “并没有给我返回信息!然而事实上,你确实给我返回了信息,信息的内容是 无信 息,也就是无返回值类型 void”。具体的程序如下: int myAge = 0; int a=20; void remAge(int a){ myAge=a; } 具体的函数说明如下: int myAge =0; //定义并初始化我的年龄为 0; int a=20; /*定义变量 a 等于 20*/ void /*返回值类型为无返回值类型*/ remAge /*函数名称*/(int a /*传入 的参数*/){ myAge=a; //内部实现方法,注意,没有 return 返回!!! } 关于函数的话题还有很多很多,这里就不一一介绍了,我的目的是让你知道函 数是怎么一会事儿!为下面的讨论作铺垫! 1.3 指针以及引用: 指针及引用是在 C++中有的,JAVA 中没有。JAVA 中取消了对内存的操作,随之 而来的事也取消了操作符重载的操作。不过在稍候我还是会介绍一些操作符重载的 功能等。引用主要还是用在函数参数的传递上。所以我在这里就不做过多的介绍了。 他们很实用,有兴趣的同学可以参阅 C++相关书籍。 .4 运算符及控制语句: 还是自己看看相关书籍吧,这里就不再熬述了! 2.深入探讨面向对象: 2.1“ ”类型 的内部细节: 有了上面的知识,我们现在就可以深入的挖掘类的内部实现了。所有的知识点 我都会围绕着类与对象展开,在此之前,我希望你能够确信对以上所介绍的基本内 容已完全掌握了! 是的,面向对象的编程语言最大的特色就是可以编写自己所需的数据类型,以更好 “”的解决问题。我想我必须要帮你搞清楚 类,对象,属性,方法它们之间的关系 ! “”“”就像我前面所说的,人这个 类 是什么也做不了的,因为 人类 只是一个抽象的概 “”“”“”念,它不是实实在在的 东西 ,而这个 东西 就是所谓的对象。只有人这个 对象 才能去工作。而类呢?类是对象的描述!对象从类中产生出来!此时,对象具有类 所描述的所有的属性以及方法。-------一定要理解这句话!!! 也许你已经有些不知所措了,没关系!好好的回味一下,我再举个例子!例如 电视机,电视机都有工作原理图,那么什么叫电视机呢?只要它能够实现工作原理 图的所有功能的物体,我们都叫它电视机。你想想是不是这么一回事儿?可是,电 “视机原理图是不能工作的,也就是这个原理图不能收看节目,只有电视机这个 实 ——体 即所谓的对象”才能收看节目,也就是说,从类生成出对象之后才算得上是 真正的有意义!才能开始工作。此时,电视机拥有电视原理图所描述的所有的属性 及方法!明白了吧,呵呵! 我先前介绍过,类是属性与方法的集合。而这些属性与方法可以被声明为私有 的(private),公共的(public)或是受保护(protected)的,他们描述了对类成员 的访问控制。下面我分别做一下介绍: 1. 公共的(public):把变量声明为公共类型的之后,那么就可以通过 对象来直接访问,一切都是暴露无遗的!也就是说,你的信用卡密码别 人也能够直接得到。 2. 私有的(private):如果把变量声明为私有的情况就好多了,想要 得到我的信用卡密码,对象必须要调用专用的方法才能够得到。 3. 受保护的(protected):介绍继承时再讨论。 4. 默认控制访问符(friendly)://JAVA 中有而 C++中没有。 为了实现数据的封装,提高数据的安全性,我们一般会把类的属性声明为私有的, 而把类的方法声明为公共的。这样,对象能够直接调用类中定义的所有方法,当对 象想要修改或得到自己的属性的时候就必须要调用以定义好的专用的方法才能够实 现。你想想,你会把你的信用卡密码公布出来嘛?呵呵!所以,我们提倡的是: “对象调方法,方法改属性”; 2.2 通过实例看内存分配: 说了这么多,让我们来看一个实例吧!比如:现在我们要编写某家公司员工管理系 统,你认为最合适的数据类型是什么?我认为是员工个人!但是在面向过程的语言 中,这样做是不允许的,因为它只能使用语言中的内部数据类型!而员工不在这个 内部数据类型之内!也许有人会说可以用 C 语言中的 struct,好注意!毕竟它是 类的基础!如果你以前是一名面 C 或 B 的程序员,请你忘掉这些,让我们一起看 看如何用类来实现这一切吧! 某家公司的员工是人类的一个特殊群体,它除了具备人类的所有特性与方法外, 它还有额外的特性与方法,比如她有她的工资、信用卡密码、作息时间等等,这些 特性以及工作内容,工作量等等这些方法。而在计算机中我们该如何定义这个类呢? 下面我将写出它的格式,让你看看在计算机中它是张什么样子的! /*在此我需要再次声明的是,我用的是 JAVA 格式,在语法格式上它与 C++大不 相同!许多细节以及内部操作都有诸多区别,而在思想上确实大同小异的*/ //employee.java public class employee{ private String name; //员工姓名 private int age; //员工年龄 private char sex; //员工性别 private float emolument; //员工薪水 private boolean lunch; //员工午餐 //……等等 public void heater(){ //这个方法是用来加工员工的午餐 lunch = true; } public void setName(String a){ //这个方法是修改员工的姓名 name= a; } public String getName(){ //这个方法是得到员工的姓名 return name; } //……等等 } 这样我们就定义完了我们所需要的数据类型。现在,让我们来看看它能够干什 么以及怎么工作! “我想要做的是,工作室里有一个光杆司令叫 jingwei”,我修改它的名字后对 对它进行输出,看看我是怎么做的吧! “注意:请仔细观察对象是如何调用方法的,它使用了 .”操作符!事实上是这样 “的,对象调用公共的属性或方法时就会使用 .”操作符。 然而在 C++中,如果定义一个同类型的指针,该指针调用此对象的方法时, “就会使用 ->”操作符。更详细的内容清参阅相关书籍了! //workstation.java import java.awt.Graphics; import java.applet.Applet; public class workstation extends Applet{ private employee jingwei ; //对象的声明,此时并不分配内存! public void init(){ private String name; //员工姓名 private int age; //员工年龄 private char sex; //员工性别 private float emolument; //员工薪水 private boolean lunch; //员工午餐 //……等等 public void heater(){ //这个方法是用来加工员工的午餐 lunch = true; } public void setName(String a){ //这个方法是修改员工的姓名 name= a; } public String getName(){ //这个方法是得到员工的姓名 return name; } //……等等 } 这样我们就定义完了我们所需要的数据类型。现在,让我们来看看它能够干什 么以及怎么工作! “我想要做的是,工作室里有一个光杆司令叫 jingwei”,我修改它的名字后对 对它进行输出,看看我是怎么做的吧! “注意:请仔细观察对象是如何调用方法的,它使用了 .”操作符!事实上是这样 “的,对象调用公共的属性或方法时就会使用 .”操作符。 然而在 C++中,如果定义一个同类型的指针,该指针调用此对象的方法时, “就会使用 ->”操作符。更详细的内容清参阅相关书籍了! //workstation.java import java.awt.Graphics; import java.applet.Applet; public class workstation extends Applet{ private employee jingwei ; //对象的声明,此时并不分配内存! public void init(){ jingwei = new employee(); /*此时创建对象会调用构造函数,稍候介绍*/ jingwei.setName(“jw”); //设置我的名字 } public void paint(Graphics g){ g.drawString("my age is "+jingwei.getName(),10,10);//显示 我的年龄 } } 输出结果是: my name is jw 这串字符串是在输出窗口的 x 坐标轴为 10 px , y 坐标轴为 10 px 的位置。 我现在要做的是,把上面的程序做个大解剖,让你能够看清楚它到底是怎么一 回事儿!(我可不时带你去看里面的汇编,呵呵,那个我也不会:) 首先还是来看看我们自定义的数据类型 employee,在应用的时候它和 int 类型 的数据没什么两样,一样的需要创建变量(对象),只不过前者是咱自己定义的, 而后这是它内置的。Employee 这个类中有许多属性,也有许多方法。而此时,我 们不能直接用我们所创建出来的对象调用它的属性进行修改。因为它是 private 受 保护类型的!我要想修改我的姓名我就要用对象调用 setName()这个方法,而我 想得到我的姓名就要调用 getName()这个方法。我们完全是按照航线来行走的, “这个航线就是 对象调方法,方法改属性” 好的,我真的相信你已经明白了这是怎么一回事儿了!呵呵!仰起航帆,继续前 行! 现在让我们一起来看看 workstation 这个类。这是个主类,和 C++中的 main()函数的味道差不多。其中,在 JAVA 中,一个文件只允许有而且必须有一 个主类,这个主类用 public 来声明!他就跟 C++中必须要有一个 main()函数是 一样的。 让我们来看看这个类中的第一条语句!private employee jingwei ;这条语 句的作用是声明一个 employee 的对象 jingwei(在 C++中就不用声明了)。我 “”“”想要和你说的是 声明 与 定义 之间的区别。声明只是告诉计算机将要有这样的一 个变量(对象),在内存中它并不为这个变量(对象)分配内存!而只有在定义的 时候才会给这个变量(对象)分配内存。(需要说明一下的是 init()方法是完成初 始化操作的,在此处定义对象,为对象分配内存。start()方法用来启动浏览器的 主线程,paint()方法来显示 Apple 的界面。这些是 Applet 程序所需的,至于 Application 程序就不需要了,当然了,C++中也不需要他们。关于他们的详细内 容清参阅相关书籍) 面向对象编程,我的思想(2) 剑在鞘! 发表于 2005-9-12 18:01:00 紧接着就开始定一个对象了,对 jingwei 这个对象进行操作才会有实际的意义。千 “万不要有这种想法: 试图对类进行操作!”就像前面我说的,电视机原理不能看电 视一样!这是毫无意义的!看这条语句 jingwei = new employee();它的意思就 是定义一个 employee 类型的对象 jingwei “。此时,我想告诉你的是: jingwei ”这个对想拥有了些什么 。它拥有了类所描述的所有的属性及方法。下面我一一给 你列出来: /*所有的 employee 对象都拥有这些属性。每创建一个对象就会从新分配一块 “”内存来存放相应对象的这些属性。我的意思是每个对象都有自己 独特 的一份*/ private String name; //员工姓名 private int age; //员工年龄 private char sex; //员工性别 private float emolument; //员工薪水 private boolean lunch; //员工午餐 /*所有的 employee 对象都拥有这些方法。但在内存中只有一份*/ public void heater(){ //这个方法是用来加工员工的午餐 lunch = true; } public void setName(String a){ //这个方法是修改员工的姓名 name= a; } public String getName(){ //这个方法是得到员工的姓名 return name; } /*但是,实际上在创建 jingwei 这个对象时计算机只给这个对象的所有的属性 分配了内存,而并没有给方法分配内存。方法只有一个,是属于所有的对象的,所 以无论创建了多少个对象,计算机只会为一个方法分配一块内存。*/ 我想我还是举个例子吧,不然你非晕倒不可。呵呵! “看我这条语句 private boolean lunch;”公司不管午餐,每个员工都需要带饭。 我们现在这样想,公司的空间是所有的内存容量,你的办公桌就是计算机中的内存 中的一部分(每个员工都有一份,是在创建对象时分配的)。你把午饭带到了公司, “”放在了你的办公桌上。 午饭 占据了你的办公桌的一角( “”占了你自己 对象 的一块 内存容量)。这份午饭只属于你自己,同样别人的也只属于她自己!所以每个员工 (对象)都需要一快空间(内存)来存放自己的午餐(属性)。在计算机中也是这 “ ——样的,每创建一个对象,就会在内存中从新分配一块内存来放 午餐 lunch”这 个属性(对象所拥有的所有的属性)。 计算机只会为对象的属性分配内存。因为每个对象的都不一样!就像你往公司 带的午饭和我往公司带的午饭不一样是一个道理!但方法就不同了。早晨带的饭中 午就凉了,你需要用微波炉来加热。微波炉可不用你带,公司就有(只占公司的一 块空间),它放在了午餐桌上。你想想,微波炉属于谁的?它属于所有员工的!因 为每个员工都可以用它。而不必每个员工都带一份。由此可见,每个员工(对象) 都有一份午饭(属性),但所有的员工(对象)只一个微波炉(方法)。所有的员 工(对象)都可以通过这个微波炉(方法)来改变自己午餐(属性)的冷热状态。 殊途同归!在计算机中也就是这样,方法只有一份,供所有的对象使用!而属性是 每个对象一份,因为每个对象的都不一样。别和我说你还不明白,不然我会撞墙的, 呵呵:) 2.3 深入探讨函数:    2.3.1 构造函数、默认构造函数、 缺省构造函数      对于上面的实例,它已经能完成绝大部分工作了,但它还是不完善的,还有许 许多多的细节等到我们去完善!也许有的同学已经注意到了,当我创建完 “jingwei”这个对象时,这个对象的所有的属性都是空的,也就是说:这个对象的 姓名是未定的、年龄是未定的、性别是未定的、薪水是未定的、午餐也是未定的。 而我们想把这些属性都添加上去,就还要用对象调用相应的方法,去一个个修改! 天啊,这简直是太麻烦了!有没有什么好方法能够在我们创建对象的同时就完成了 对属性赋值的操作呢?哦不,构造函数是对属性的初始化呢?当然没问题了,这 就需要所谓的!      构造函数是类中最特殊的函数,它与析构函数的功能正好相反!      从特征上来说:1.它是编程语言中唯一没有返回值类型的函数。      2.它的名称与类的名称必须要完全相同。      3.它必须被声明为公共(public)的类型      4,可以对构造函数进行重载。      5.它在创建对象是自动被调用。      从功能上来说:1.它是对类中的属性进行初始化。      其实,对于上面的程序来说我们没有自己定义构造函数。但是,在这种情况下, “”系统会自动为我们定义一个 默认构造函数 。他会把数值变量自动赋值为 0,把布 尔行变量赋值为 false 等等(但在 C++中,默认构造函数不初始化其成员)。如 果程序员定义了构造函数,那么系统就不会再为你的程序添加一个缺默认造函数了。 (在这里,我们提倡的是自己定义构造函数,而不是用系统的默认构造函数)      还是看个实例吧!这样比较清楚一些!   //employee.java      public class employee{      private String name; //员工姓名      private int age; //员工年龄      private char sex; //员工性别      private float emolument; //员工薪水      private boolean lunch; //员工午餐      //……等等      public employee(){ // “”这个就是 默认 构造函数      name = “jw”; //设置员工姓名      age = 20; //设置员工年龄      sex = “M”; //设置员工性别      emolument = 100; //设置员工薪水      lunch = false; //设置员工午餐      }      public void heater(){ //这个方法是用来加工员工的午餐      lunch = true;      }      //……等等      }; “这样,在我们创建 jingwei”这个对象的同时,它的所有的属性也被初始化了!显 然,这大大的提高了工作效率,但是,它还是不符合要求。想想看,如果我们现在 “”创建这个类型的第二个对象的时候会发生什么事情?告诉你,除了对象的 名 (这 “个名称不在是对象属性中的名称,而是对象本身的名称)不一样外,其所有的 属 ”性值 都一样!比如:现在我们创建第二个对象 flashmagic,然而我会发现这个对 象的所有的属性和 jingwei 这个对象的所有的属性完全相同。而我们只能在用对象 的方法去改变着写属性了!很显然,这种方法不大好!我们需要一种方法在创建对 “”象的时候为对象的属性赋予 我们想要的值 。      相信你也看到了,默认构造函数就显得无能为力了。我们需要的是带参数的构 造函数,在创建对象时,我们把参数传给构造函数,这样就能完成了上述的功能! 口说无凭,还是来看个实例吧:      //employee.java      public class employee{      private String name; //员工姓名      private int age; //员工年龄      private char sex; //员工性别      private float emolument; //员工薪水      private boolean lunch; //员工午餐      //……等等      public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数      name = n; //设置员工姓名      age = a; //设置员工年龄      sex = s; //设置员工性别      emolument = e; //设置员工薪水      lunch =l; //设置员工午餐      }      public void heater(){ //这个方法是用来加工员工的午餐      lunch = true;      }      //……等等      };      这样一来,在创建对象的同时我们就可以给他赋予我们想要的值,很显然,这 可就方便多了。哦,对了!还没有告诉你怎么创建呢!哈哈,往前翻几页你会看到 这句话:      jingwei = new employee();这是创建一个对象,而我们把它改成      jingwei = new employee("jingwei",20,'M',100,false);这样一来,所有 “”的工作都完成了,呵呵!(在创建对象的同时赋予了我们想要的 初值 )    2.3.2 重载构造函数:      我还是先把概念给你吧,让你有个认识,随后我们在进行论述。      在 JAVA 中:      1. 函数重载是一个类中声明了多个同名的方法,但有不同的参数个数和参数 类型。      2. 函数重构是指在子类中声明与父类同名的方法,从而覆盖了父类的方法。 重构解决了子类与父类的差异问题。(在讨论到继承时我会详细说明)      在 C++中:      1 . 数重载的概念一样。      2 . 重构的概念可就不一样了,C++中功能更为庞大的虚函数。更详细内容 这里就不错过多介绍了! 其实关于重载的概念你并不陌生,在编程中相信你也接触过。呵呵!让我们来举个 操作符重载的例子你就会明白了,(JAVA 中不支持这个功能)我们定义三个整数 变量:      int i1=2, i2=3,i3=0;      i3 = i1 + i2;      此时 i3=5;加号实现了两个数相加的运算功能。然而我们现在要定义三个字符 串变量:      String str1=”jing”, str2=”wei”,str3=””;      str3 = str1 + str2;      此时 str3 = “jingwei”;加号实现了两个字符串相加的运算功能。同样是加号, 既可以把两个整型的变量加在一起,也可以把两个字符串类型的变量加在一起。同 一个操作符实现了不同的功能------这就是所谓的操作符重载(嘿嘿,我说你一定 见过吧:)!不就好像是汉语中的一词多意一样!我需要说明一下的是,C++中 的操作符重载可没有这么简单。比如,我们可以对两个自定义类型的对象进行相加 的运算,进行赋值的运算。这样书写简洁明了,而且非常实用。当然,关于操作符 重载的话题太多了,有兴趣再看看书吧!    “”  我们把操作符的话题在转到函数上来,我们一直强调的是 对象调方法 ------ “”对象其实调的是方法的 名称 。而我们现在要对方法进想重载,也就是定义多个相 同名称的函数,这样计算机在调用的时候不会混淆嘛?我想应该不会的,呵呵,因 为仅仅是函数名称相同,而我们在调用函数时会把参数传递给他的。既是没有参数 也是一种参数传递参数的信息(信息为无参数)!然而由于参数类型、参数数量、 返回值类型不同我们就可以对相同名称的函数进行区分了!目的只有一个,用简便 的方法实现更多的功能。还是举个例子吧,重载构造函数!      public class employee{      public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数      name = n; //设置员工姓名      age = a; //设置员工年龄      sex = s; //设置员工性别      emolument = e; //设置员工薪水      lunch =l; //设置员工午餐      }      public employee(){ //请注意这个函数没有参数      name = “jw”;      age = 20;      sex = ’W’;      emolument = 99;      lunch = true      }      //……等等      };      看,在一个类中有两个名称相同的函数,可我们在使用的时候系统如何知道我 们调用的是那个版本的函数呢?呵呵,我刚刚说过了,可以通过函数的参数类型、 参数数量、返回值类型来确定。现在我们接着试验,我们创建两个对象其中的一个 调用带参数的构造函数,第二个对象调用缺省值的构造函数。我们来看看结果:      jingwei = new employee("jingwei",20,'M',100,false);/*创建这个对象 的时候调用的是带参数的构造函数*/      flashmagic = new employee();//创建这个对象是调用的是却省值的构造 函数      而得到的结果呢?让我们一起来看一看!      Jingwei 这个对象中: flashmagic 这个对象中:      name jingwei name jw 其实关于重载的概念你并不陌生,在编程中相信你也接触过。呵呵!让我们来举个 操作符重载的例子你就会明白了,(JAVA 中不支持这个功能)我们定义三个整数 变量:      int i1=2, i2=3,i3=0;      i3 = i1 + i2;      此时 i3=5;加号实现了两个数相加的运算功能。然而我们现在要定义三个字符 串变量:      String str1=”jing”, str2=”wei”,str3=””;      str3 = str1 + str2;      此时 str3 = “jingwei”;加号实现了两个字符串相加的运算功能。同样是加号, 既可以把两个整型的变量加在一起,也可以把两个字符串类型的变量加在一起。同 一个操作符实现了不同的功能------这就是所谓的操作符重载(嘿嘿,我说你一定 见过吧:)!不就好像是汉语中的一词多意一样!我需要说明一下的是,C++中 的操作符重载可没有这么简单。比如,我们可以对两个自定义类型的对象进行相加 的运算,进行赋值的运算。这样书写简洁明了,而且非常实用。当然,关于操作符 重载的话题太多了,有兴趣再看看书吧!    “”  我们把操作符的话题在转到函数上来,我们一直强调的是 对象调方法 ------ “”对象其实调的是方法的 名称 。而我们现在要对方法进想重载,也就是定义多个相 同名称的函数,这样计算机在调用的时候不会混淆嘛?我想应该不会的,呵呵,因 为仅仅是函数名称相同,而我们在调用函数时会把参数传递给他的。既是没有参数 也是一种参数传递参数的信息(信息为无参数)!然而由于参数类型、参数数量、 返回值类型不同我们就可以对相同名称的函数进行区分了!目的只有一个,用简便 的方法实现更多的功能。还是举个例子吧,重载构造函数!      public class employee{      public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数      name = n; //设置员工姓名      age = a; //设置员工年龄      sex = s; //设置员工性别      emolument = e; //设置员工薪水      lunch =l; //设置员工午餐      }      public employee(){ //请注意这个函数没有参数      name = “jw”;      age = 20;      sex = ’W’;      emolument = 99;      lunch = true      }      //……等等      };      看,在一个类中有两个名称相同的函数,可我们在使用的时候系统如何知道我 们调用的是那个版本的函数呢?呵呵,我刚刚说过了,可以通过函数的参数类型、 参数数量、返回值类型来确定。现在我们接着试验,我们创建两个对象其中的一个 调用带参数的构造函数,第二个对象调用缺省值的构造函数。我们来看看结果:      jingwei = new employee("jingwei",20,'M',100,false);/*创建这个对象 的时候调用的是带参数的构造函数*/      flashmagic = new employee();//创建这个对象是调用的是却省值的构造 函数      而得到的结果呢?让我们一起来看一看!      Jingwei 这个对象中: flashmagic 这个对象中:      name jingwei name jw 其实关于重载的概念你并不陌生,在编程中相信你也接触过。呵呵!让我们来举个 操作符重载的例子你就会明白了,(JAVA 中不支持这个功能)我们定义三个整数 变量:      int i1=2, i2=3,i3=0;      i3 = i1 + i2;      此时 i3=5;加号实现了两个数相加的运算功能。然而我们现在要定义三个字符 串变量:      String str1=”jing”, str2=”wei”,str3=””;      str3 = str1 + str2;      此时 str3 = “jingwei”;加号实现了两个字符串相加的运算功能。同样是加号, 既可以把两个整型的变量加在一起,也可以把两个字符串类型的变量加在一起。同 一个操作符实现了不同的功能------这就是所谓的操作符重载(嘿嘿,我说你一定 见过吧:)!不就好像是汉语中的一词多意一样!我需要说明一下的是,C++中 的操作符重载可没有这么简单。比如,我们可以对两个自定义类型的对象进行相加 的运算,进行赋值的运算。这样书写简洁明了,而且非常实用。当然,关于操作符 重载的话题太多了,有兴趣再看看书吧!    “”  我们把操作符的话题在转到函数上来,我们一直强调的是 对象调方法 ------ “”对象其实调的是方法的 名称 。而我们现在要对方法进想重载,也就是定义多个相 同名称的函数,这样计算机在调用的时候不会混淆嘛?我想应该不会的,呵呵,因 为仅仅是函数名称相同,而我们在调用函数时会把参数传递给他的。既是没有参数 也是一种参数传递参数的信息(信息为无参数)!然而由于参数类型、参数数量、 返回值类型不同我们就可以对相同名称的函数进行区分了!目的只有一个,用简便 的方法实现更多的功能。还是举个例子吧,重载构造函数!      public class employee{      public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数      name = n; //设置员工姓名      age = a; //设置员工年龄      sex = s; //设置员工性别      emolument = e; //设置员工薪水      lunch =l; //设置员工午餐      }      public employee(){ //请注意这个函数没有参数      name = “jw”;      age = 20;      sex = ’W’;      emolument = 99;      lunch = true      }      //……等等      };      看,在一个类中有两个名称相同的函数,可我们在使用的时候系统如何知道我 们调用的是那个版本的函数呢?呵呵,我刚刚说过了,可以通过函数的参数类型、 参数数量、返回值类型来确定。现在我们接着试验,我们创建两个对象其中的一个 调用带参数的构造函数,第二个对象调用缺省值的构造函数。我们来看看结果:      jingwei = new employee("jingwei",20,'M',100,false);/*创建这个对象 的时候调用的是带参数的构造函数*/      flashmagic = new employee();//创建这个对象是调用的是却省值的构造 函数      而得到的结果呢?让我们一起来看一看!      Jingwei 这个对象中: flashmagic 这个对象中:      name jingwei name jw 其实关于重载的概念你并不陌生,在编程中相信你也接触过。呵呵!让我们来举个 操作符重载的例子你就会明白了,(JAVA 中不支持这个功能)我们定义三个整数 变量:      int i1=2, i2=3,i3=0;      i3 = i1 + i2;      此时 i3=5;加号实现了两个数相加的运算功能。然而我们现在要定义三个字符 串变量:      String str1=”jing”, str2=”wei”,str3=””;      str3 = str1 + str2;      此时 str3 = “jingwei”;加号实现了两个字符串相加的运算功能。同样是加号, 既可以把两个整型的变量加在一起,也可以把两个字符串类型的变量加在一起。同 一个操作符实现了不同的功能------这就是所谓的操作符重载(嘿嘿,我说你一定 见过吧:)!不就好像是汉语中的一词多意一样!我需要说明一下的是,C++中 的操作符重载可没有这么简单。比如,我们可以对两个自定义类型的对象进行相加 的运算,进行赋值的运算。这样书写简洁明了,而且非常实用。当然,关于操作符 重载的话题太多了,有兴趣再看看书吧!    “”  我们把操作符的话题在转到函数上来,我们一直强调的是 对象调方法 ------ “”对象其实调的是方法的 名称 。而我们现在要对方法进想重载,也就是定义多个相 同名称的函数,这样计算机在调用的时候不会混淆嘛?我想应该不会的,呵呵,因 为仅仅是函数名称相同,而我们在调用函数时会把参数传递给他的。既是没有参数 也是一种参数传递参数的信息(信息为无参数)!然而由于参数类型、参数数量、 返回值类型不同我们就可以对相同名称的函数进行区分了!目的只有一个,用简便 的方法实现更多的功能。还是举个例子吧,重载构造函数!      public class employee{      public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数      name = n; //设置员工姓名      age = a; //设置员工年龄      sex = s; //设置员工性别      emolument = e; //设置员工薪水      lunch =l; //设置员工午餐      }      public employee(){ //请注意这个函数没有参数      name = “jw”;      age = 20;      sex = ’W’;      emolument = 99;      lunch = true      }      //……等等      };      看,在一个类中有两个名称相同的函数,可我们在使用的时候系统如何知道我 们调用的是那个版本的函数呢?呵呵,我刚刚说过了,可以通过函数的参数类型、 参数数量、返回值类型来确定。现在我们接着试验,我们创建两个对象其中的一个 调用带参数的构造函数,第二个对象调用缺省值的构造函数。我们来看看结果:      jingwei = new employee("jingwei",20,'M',100,false);/*创建这个对象 的时候调用的是带参数的构造函数*/      flashmagic = new employee();//创建这个对象是调用的是却省值的构造 函数      而得到的结果呢?让我们一起来看一看!      Jingwei 这个对象中: flashmagic 这个对象中:      name jingwei name jw  age 20 age 20      sex M sex W      emolument 100 emolument 99      lunch false lunch true      看,虽然是两个名称完全相同的函数,但完成了不同的工作内容。呵呵!关于 函数重载我们就料到这里吧,我相信你已经有个大印象了,而更详细的内容仍需要 你的努力!      重载普通的函数与重载构造函数大同小异,不过他多了一个 this 指针!this 一般是对当前对象的引用。这么说吧,如果涉及到两个以上的对象时就会使用 this 指针。每个成员函数都有一个 this 指针,它是一个隐藏的参数,this 指针只向调 用它的对象!我说过方法只有一份,而对象都有自己的属性,当对象调用方法来先 是属性的时候,他怎么来判断调用的时不是自己的属性呢?这就需要 this 指针来 大显神威了。      关于拷贝构造函数、内联函数、虚函数、模版等欧就不做过多的讨论了,因为 JAVA 中好像没有这些了。不过我需要提醒你一下的是,在 C++中,类内定义的 函数自动转换为内联函数,而这好像与我前面提到的思想有冲突。因为内联函数的 目的是减少函数调用的开销!呵呵!我也没绕出来呢!还请哪为大虾指点一二!谢!    2.3.3 初始化与赋值      这里我却要提醒你一下的是,初始化与赋值是完全不同的两个概念。创建一个 类的时候会调用这个类的构造函数对对象的属性进行初始化。而如果以后再把这个 对象赋给其他同类型的对象时可就没那么简单了。在 JAVA 中直接赋值就行了,因 为 JAVA 中取消了指针,不存在指针的深拷贝与前拷贝问题。而在 C++中就需要 拷贝构造函数以及操作符重载了。因为 JAVA 中不牵扯这些东西,所以偶就不做过 多介绍了。详情请参阅相关书籍吧!      2.3.4 析够函数:      JAVA 中不再支持指针了,所以你感觉不到它的重要性,因为系统会自动为你 释放内存。而在 C++中一切都是手动的。在构造函数中 new 了一个指针,在析够 函数中就要 delete 这个指针。      2.3.5 静态:    “”  现在我们再来看一看 静态 是咋一回事儿!    “  把一个变量或函数声明为静态的需要 static”这个关键字。声明静态的目的是 “”为某个类的所有对象的某个属性或方法分配单一的存储空间 。静态的数据是属于 类的,不属于任何的对象。静态的数据在声明的时候系统就为他分配了内存空间, 而不用等到创建对象时。举个例子来帮你更好的理解它吧。        还是接着上面的例子。还记得刚刚我说过的员工能用微波炉热饭的事情吧。现 在我们要找一个手套,毕竟想把热好的饭从微波炉里拿出来直接下手是不行的。我 把手套定义成一个布尔型的变量,它有干净和脏两种状态。想想看手套是属于谁的? 所有对象?不对!因为只有方法才能属于所有的对象。它是属于类的,它像微波炉 那个方法一样,在内存中只有一份,所有的对象通过方法都能够修改它。而下一次 修改是基于上一次修改的基础之上的!我的意思是:一个员工把手套弄脏了,下一 个员工在使用的时候它还是脏的。而这个员工把手套洗干净之后,别人再用的时候 它就是干净的了!就这么点事儿,明白了吧!      关于静态函数我想就没什么可多说的了。给我的感觉就是,它也是属于类的, 在定义的时候就分配的内存。调用是可以使用类名直接调用。其他的和普通成员函 数没什么不同的了不过这里需要说明的一点是:在 JAVA 中,静态的成员函数只能 修改静态的属性,而静态的属性可以被所有的成员函数修改。不过在 C++中就没 这么多事儿了!      2.4 继承    “”  继承很好理解,它的最大好处就是 代码重用 ,大大提高了工作效率。举个例 子你就明白了。世界上先有的黑白电视机,它有自己的工作原理。然而人们在他的 基础之上开发出了彩色电视机。彩色电视机继承了黑白电视机的所有的特性与方法! 因为它既能显示彩色图像也能显示黑白图像。然而它与黑白电视机又有许多区别, 在工作原理上。彩色电视及多了矩阵色电路,把彩色信号分离出三种颜色 (RGB),他就能显示彩色的图像了。而黑白电视机没有这块电路,即使它收到 了彩色信号也显示不了彩色图像。彩色电视机是从黑白电视机中派生出来的。所以, 黑白电视机是父类,彩色电视既是子类,彩色电视继承了黑白电视机所有的特性与 方法。看看再计算机中它是什么样子的吧:   //BWtv.java 父类的定义      public class BWtv{      private int a;      public BWtv(){      a=1;      } public changeBWtv(int i){      a=i;      }      }      //Ctv.java 子类的定义      class Ctv exntends BWtv{ // “注意关键字 extends”      private int b;          public Ctv(){        b=2;      }      public changetCv(int x){      b = x;      }      }      有了上面的定义,我们来看看他们都有什么数据。      BWtv 的数据包括     Ctv 的数据包括      private int a     private int a                 private int b      public changeBWtv(); public changeBWtv()      public changeCtv();    ”  你看,子类拥有父类的所有的方法及属性。注意关键字 extends”,它的意思 是继承。在 C++ “”中使用的是 : 操作符。意思是一样的。但是这里有许多问题, 首先是访问权限的问题,子类的对象拥有父类的所有的属性和方法这句话。对嘛? 肯定是对的!(不过 JAVA 的书中可不是这么说的,他说只继承非 private 类型的 属性及方法,我觉得它这句话有错误!)可是,子类的对象不能直接访问父类的私 有属性或方法,它只能通过父类的公有成员函数来访问。而此时,如果你修改了父 类的属性的值。那就真的修改了。我的意思是:父类的私有属性的值会随着子类对 象调用父类的公有方法进行对相应属性的修改而发生变化!(这里面存在一个域的 问题,所有的修改都是在子类中进行的,修改的是子类继承的父类的属性(在子类 这个域中,此时父类以拷贝到子类中了。)。而程序中定义的父类的属性不会发生 任何变化(在父类的域中),)      其次是构造函数,在创建一个子类对象时首先要调用的是父类的构造函数,然 后再调用子类的构造函数,毕竟,子类的构造函数不包括父类的属性的初始化功能! “”(从这一点来说我的观点又是正确的 子类的对象拥有父类的所有的属性和方法 ) 当然了,析够函数的调用顺序正好相反!      现在让我们来谈谈 protected 这个关键字吧,它的意思是:对对象来说,声 明为 protected 的变量是私有的,而对子类父类来说,声明为 protected 的变量 是公共的。      现在又出现了这样的一个问题,如果我们在子类中也定义了一个 int 类型的变 量 a,那我们在创建子类的对象的时候调用的是子类定义的还是父类定义的呢?这 就涉及到数据的隐藏的问题了,我可以告诉你肯定是调用的子类的变量 a。因为, 子类把父类的这个同名变量给隐藏了。而如果是方法呢?这就涉及到重构的问题了, “在上面我提到过 函数重构是指在子类中声明与父类同名的方法,从而覆盖了父类 ”的方法。重构解决了子类与父类的差异问题。 这里必须要声明一下的是,在 JAVA 中,子类出现了对父类属性的隐藏和父类方法的覆盖后,在子类中,子类对象仅能 调用子类本身的属性和方法。要调用父类的属性和方法必须要实用 super 这个关 键子。而在 C++中就不这样了。因为它有虚函数 虚拟函数在 C++中非常好玩的事。我们可以把需要改写的函数声明为虚函数,用 virtual 这个关键字来声明。这样。假如如果我们 CwinApp 这么一个基类,它里面 定义了一个成员(虚)函数为 InitInstance()和另一个为(虚)函数 InitApplication()。如果我从 CWinApp 派生一个子类为 CMyWinApp 并修改了 InitInstance()这个成员函数。我们并没有修改 InitApplication()这个成员函数。 现在我们创建 CMyWinApp 这个类的函数 theApp,我们并创建一个指针*pApp 指向这个对象 theApp。此时:      pApp->InitInstance() //指针调用的是子类 CMyWinApp 的虚方法      pApp->InitApplication() //指针调用的时父类 CwinApp 的虚方法      因为子类并没有修改父类的方法,所以调用的是父类的虚方法。这就牵扯到虚 你表的问题。碍与本篇文章的定位,这里就不讨论了!        关于父类与子类的对象的类型转换问题是这样的,子类对象转换为父类对 象时,不会出现错误。因为子类包含父类的所有的属性及方法,而父类向子类转换 时就难说了,呵呵。这还会牵扯到虚拟表的问题,也不讨论了!      JAVA 中不再支持多重继承,也就是一个类从两个以上的类中继承而来,但它 “却多了接口的概念 interface”。这里就不做过多介绍了!      关于抽象基类也没什么难的!他的一个大概念就是:做为许多类的父类,不定 义对象,只做派生用!    我能做得也只有这些了,如果你能明白以上的六七成,那就是对我最大的回报了, 呵呵!就像刚刚开始我说的,我只是给你一个大概的思想,至于内部的实现细节, 仍需要你的继续努力。关于编程语言的内容还有许多许多,实属小生个人能力有限 而不能全盘照顾到。不过作为一个初学者的你来说,这些东西都是基本的。需要我 提醒你一点的是,不要指望在第一、二遍的时候看懂什么!加油:) 04.4.29 韩景维
还剩30页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

lzuniujp08

贡献于2013-04-18

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf