20120505--面向对象之多态
- 格式:docx
- 大小:205.62 KB
- 文档页数:10
第四章面向对象---类继承与多态一. 继承基础知识为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总是希望能够利用前人或自己以前的开发成果,同时又希望在自己的开发过程中能够有足够的灵活性,不拘泥于复用的模块。
C#这种完全面向对象的程序设计语言提供了两个重要的特性--继承性inheritance 和多态性polymorphism。
继承是面向对象程序设计的主要特征之一,它可以让您重用代码,可以节省程序设计的时间。
继承就是在类之间建立一种相交关系,使得新定义的派生类的实例可以继承已有的基类的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起类的新层次。
现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征也存在内在的差别。
人们可以采用层次结构来描述这些实体之间的相似之处和不同之处。
图1 类图上图反映了交通工具类的派生关系。
最高层的实体往往具有最一般最普遍的特征,越下层的事物越具体,并且下层包含了上层的特征。
它们之间的关系是基类与派生类之间的关系。
为了用软件语言对现实世界中的层次结构进行模型化,面向对象的程序设计技术引入了继承的概念。
一个类从另一个类派生出来时,派生类从基类那里继承特性。
派生类也可以作为其它类的基类。
从一个基类派生出来的多层类形成了类的层次结构。
注意:C#中,派生类只能从一个类中继承。
这是因为,在C++中,人们在大多数情况下不需要一个从多个类中派生的类。
从多个基类中派生一个类这往往会带来许多问题,从而抵消了这种灵活性带来的优势。
C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。
除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。
看下面示例:using System ;class Vehicle //定义交通工具(汽车)类{protected int wheels ; //公有成员:轮子个数protected float weight ; //保护成员:重量public Vehicle( ){;}public Vehicle(int w,float g){wheels = w ;weight = g ;}public void Speak( ){Console.WriteLine( "交通工具的轮子个数是可以变化的! " ) ;}} ;class Car:Vehicle //定义轿车类:从汽车类中继承{int passengers ; //私有成员:乘客数public Car(int w , float g , int p) : base(w, g){wheels = w ;weight = g ;passengers=p ;}}Vehicle 作为基类,体现了"汽车"这个实体具有的公共性质:汽车都有轮子和重量。
简述面向对象中的多态
面向对象中的多态是指一个对象可以以多种形态存在。
简单来说,多态就是同一个方法可以有不同的实现方式。
在面向对象的程序设计中,多态是一种非常重要的概念。
它能够提高代码的灵活性和可扩展性,使得代码更易于维护和扩展。
多态的实现方式主要有两种:静态多态和动态多态。
静态多态是通过函数的重载和运算符的重载来实现的。
函数的重载是指在同一个类中定义多个同名函数,但这些函数具有不同的参数列表。
运算符的重载是指对于某个运算符,可以定义多个不同的操作方式。
在编译时,编译器会根据调用时的参数类型来确定具体调用的函数或运算符。
动态多态是通过继承和虚函数来实现的。
继承是指子类可以继承父类的属性和方法,通过定义一个指向父类对象的指针或引用,可以调用子类对象中重写的方法。
虚函数是在父类中声明为虚函数的函数,子类可以对其进行重写。
在运行时,根据实际对象的类型来调用相应的方法。
多态具有很多优点。
首先,它可以提高代码的重用性,一个类的方法可以被多个类继承并重写,这样可以减少代码的重复编写。
其次,多态可以使代码更加灵活,可以根据需要动态地根据对象的类型来调用相应的方法。
再次,多态可以提高代
码的可扩展性,当需要添加新的功能时,只需要在子类中重写相应的方法即可,而不需要修改已有的代码。
总之,多态是面向对象编程中非常重要的概念,通过使用多态可以使代码更灵活、可扩展和易于维护。
它是面向对象编程中的重要特性之一,值得我们深入理解和应用。
解释面向对象程序设计中封装、继承、多态的概念【解释面向对象程序设计中封装、继承、多态的概念】在面向对象程序设计(Object-Oriented Programming,OOP)中,封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)是三个非常重要的概念,它们构成了OOP的基础。
在本文中,我将深入探讨这些概念,并通过具体的案例和应用来加深理解。
一、封装(Encapsulation)1.1 定义:封装是指将数据和方法打包在一起,同时对外隐藏对象的内部状态。
这样外部程序只能通过对象提供的接口(方法)来访问数据,而不能直接对数据进行操作。
1.2 实例:举一个简单的例子,比如一个汽车类。
我们可以将汽车的速度、油量等属性以及加速、刹车等方法封装在一个类中,并提供公共的接口供外部程序调用。
这样在使用汽车的时候,不需要关心汽车内部的具体实现,只需通过接口来操作汽车即可。
1.3 个人观点:我认为封装是OOP中非常重要的概念,它可以有效地提高代码的可维护性和安全性。
封装也使得对象的实现细节对外部程序透明,从而降低了程序的耦合度,提高了代码的灵活性。
二、继承(Inheritance)2.1 定义:继承是指一个类可以从另一个类中继承属性和方法,并且可以在此基础上进行扩展和修改。
这样可以有效地实现代码的复用,提高了代码的可维护性和可扩展性。
2.2 实例:以动物类和猫类为例,动物类中包含了一些通用的属性和方法,比如呼吸、进食等。
而猫类可以从动物类中继承这些属性和方法,并且可以在此基础上扩展一些猫特有的属性和方法,比如捉老鼠、喵喵叫等。
2.3 个人观点:继承是OOP中非常重要的特性,它可以帮助程序员减少重复代码的编写,提高了代码的复用性和可维护性。
但是在具体应用时,需要注意合理使用继承,避免过度继承导致代码结构复杂和不易理解。
三、多态(Polymorphism)3.1 定义:多态是指同一操作作用于不同的对象上会产生不同的行为。
面向对象的多态什么是多态在面向对象编程中,多态(Polymorphism)是一个重要的概念。
它指的是同一个方法可以根据不同的对象产生不同的行为。
换句话说,多态允许我们使用统一的接口来处理不同类型的对象。
多态是面向对象编程的三大特性之一,其余两个特性是封装和继承。
封装是指将数据和方法包装在一个对象中,继承是指一个类可以继承另一个类的属性和方法。
多态使得程序更加灵活,可扩展性更强。
生活中的多态示例为了更好地理解多态,我们可以通过生活中的一些例子来解释它。
1. 动物发声想象一下,你在一座动物园里散步。
你经过了一些动物的笼子,每个动物都在发出自己独特的声音。
狗在汪汪叫,猫在喵喵叫,鸟在唧唧鸣。
尽管它们发出的声音不同,但它们都是动物,都具有发声的能力。
在这个例子中,动物园可以被看作是一个类,而每个动物则是该类的实例。
类定义了动物的共同属性和方法,而每个实例则可以根据自己的特性来表现不同的行为。
这就是多态的体现。
2. 图形的面积计算假设你正在画一些图形,包括圆形、矩形和三角形。
你需要计算每个图形的面积。
不同的图形有不同的计算公式,但它们都有一个共同的方法——计算面积。
在这个例子中,每个图形可以被看作是一个类,而计算面积的方法则是这个类的一个公共方法。
每个图形类可以根据自己的特性实现不同的计算面积的方式。
当你调用计算面积的方法时,程序会根据具体的图形类型来执行相应的计算。
多态的实现方式在面向对象编程中,实现多态有两种常见的方式:继承和接口。
1. 继承实现多态继承是面向对象编程中的一个重要概念,它允许一个类继承另一个类的属性和方法。
通过继承,子类可以重写父类的方法,从而实现多态。
以动物为例,我们可以定义一个基类 Animal,它有一个方法叫做 makeSound()。
然后我们定义几个子类,如 Dog、Cat 和 Bird,它们分别重写了 makeSound() 方法来发出不同的声音。
class Animal {public void makeSound() {System.out.println("Animal makes sound");}}class Dog extends Animal {@Overridepublic void makeSound() {System.out.println("Dog barks");}}class Cat extends Animal {@Overridepublic void makeSound() {System.out.println("Cat meows");}}class Bird extends Animal {@Overridepublic void makeSound() {System.out.println("Bird chirps");}}public class Main {public static void main(String[] args) {Animal dog = new Dog();Animal cat = new Cat();Animal bird = new Bird();dog.makeSound(); // 输出:Dog barkscat.makeSound(); // 输出:Cat meowsbird.makeSound(); // 输出:Bird chirps}}在上面的例子中,我们定义了一个 Animal 类作为基类,然后定义了三个子类 Dog、Cat 和 Bird,它们都重写了 makeSound() 方法。
什么是多态?⾯向对象程序设计为什么要引⼊多态的特
性?使⽤多态有什么优点
多态是指程序中同名的不同⽅法共存的情况。
多态是⾯向对象程序设计的⼜⼀个特性。
我们知道,⾯向过程的程序设计中,过程或函数各具有⼀定的功能它们之间是不允许重名的;⽽⾯向对象程序设计中,则要利⽤这种多态来提⾼程序的抽象性,突出Java语⾔的继承性。
⾯向对象的程序中多态的情况有多种,可以通过⼦类对⽗类⽅法的覆盖实现多态,也可以利⽤重载在同⼀个类中定义多个同名的不同⽅法。
多态的特点⼤⼤提⾼了程序的抽象程度和简洁性,更重要的是它最⼤限度地降低了类和程序模块之间的耦合性,提⾼了类模块的封闭性,使得它们不需了解对⽅的具体细节,就可以很好地共同⼯作。
这个优点,对程序的设计、开发和维护都有很⼤的好处。
面向对象程序设计中的多态性实现与应用随着计算机技术的不断发展,面向对象程序设计成为了当前主流的编程方法。
在面向对象程序设计中,多态性是一个重要的概念,它能够让程序具有更好的灵活性和可扩展性。
本文将介绍面向对象程序设计中多态性的实现方法以及应用场景。
一、多态性的概念多态性是指一种对象或方法能够表现出多种形态的能力。
在面向对象编程中,多态性通常与继承和接口有关,通过这些方式实现多态性。
多态性的主要目的在于增强程序的灵活性和可扩展性,减少代码的重复性,同时也有助于编写更加清晰简洁的代码。
二、实现多态性的方法下面将介绍实现多态性的两种主要方法,即继承和接口。
1. 继承继承是一种实现多态性的常用方法。
当一个类继承自另一个类时,它会自动继承父类中的属性和方法,并且可以在子类中对父类方法进行重写。
例如,我们定义了一个 Animal 类,并定义了一个 speak 方法,那么 Cat 类和Dog 类都可以继承 Animal 类,并在自己的类中重新定义自己的 speak 方法,从而实现不同的叫声。
2. 接口接口是一种定义行为的规范,它定义了一系列方法,但并不包含实现。
当一个类实现某个接口时,它必须实现该接口定义的所有方法。
接口使得不同的类能够拥有相同的行为,从而实现多态性。
例如,我们定义了一个 Shape 接口,其中定义了一个 draw 方法,然后定义了一个 Circle 类和一个Rectangle 类,它们都实现了 Shape 接口,并分别实现了自己的 draw 方法。
三、应用场景多态性在编程中有很多应用场景,下面着重介绍几个常见的应用场景。
1. 减少代码的重复性通过继承和接口的使用,我们可以避免在不同的类中重复编写相同的代码,从而减少代码的重复性。
例如,在定义不同的动物类时,我们可以让它们继承自Animal 类,从而避免重复编写相同的方法。
2. 提高灵活性和可扩展性通过使用多态性,我们可以实现程序的灵活性和可扩展性。
面向对象之多态——见人说人话,见鬼说鬼话抽象,继承,多态是面向对象的三大特性,本文将从几个问题出发,来慢慢揭下多态神秘的面纱。
Q1:什么是多态?在自然科学中很多名词都可以通过顾名思义来了解其含义。
所谓“多态”,就是有多种状态。
在具体来说就是同一个方法有多种状态,同一个函数有多种实现方式。
在面向对象(C++)中,可以通过函数重载以及虚函数来实现多态。
叙述问题:对于多态的含义,还是没有能够清晰严谨的进行表达好!!文中图表太少,文字太多,以后自己写完之后,希望能够自己阅读,对其不断反问自己,是否准确表达自己的意思!!!通俗的理解多态,就是一个“多面手”,在不同的场合,表现出不同的“范儿”。
在父母面前是一个乖乖女,在男朋友面前是小鸟依人状,在朋友面前女侠范,在老板面前把自己当男孩使……最近在网上看到一段话,这女孩可让大家更好理解多态,跟大家分享下~ “老娘这么好的一个姑娘,可直可弯能屈能伸,卖得了萌,耍得了二,扮得了少女,演得了女王,晒得了下限,红得了脸颊,玩得了小清新,咽得下重口味,斥退过死皮赖脸的无知少年,躲过了不怀好意的搭讪大叔,你讲笑话我可以拍桌大笑,你要玩文艺我仰望星空。
得之你幸,失之你命”Q2:那么多态有什么作用,什么情况下使用?多态主要有以下三个方面的作用,并且将以一个程序实例进行阐述。
(1)使得一个方法有多种实现方式(2)将接口与实现隔离,将“what”与“how”隔离开(3)方便扩展现在我们创建按如下图所示,创建乐器类及其分支。
图乐器的分类假如我们女孩子想要找一个具有“十项全能”的帅哥做男朋友,集“高富帅”于一身,想其给我们展示十八般武艺,吹拉弹唱,样样精通。
这时候其就需要多态的特性,不同乐器的演奏方式是不同的,管乐器用来吹的,弦乐器用来拉或是弹的,而打击乐器是用来敲击的。
那么这个帅哥这个接口就要调用不同的乐器play的实现方式(这为作用1)。
如果我们想要这个帅哥还能跳舞,或是学一样新乐器,我们不需要更换这个帅哥男朋友,只要让其大脑去学习这种新乐器,也就是创建一个继承于基类(大脑学习)的新类(学跳舞,或学新乐器)(此为作用3)。
如果我们特别喜欢帅哥给我们吹萨克斯那深情的样子,我们可以让其深入学习(完善实现方式。
)由于接口与实现是隔离的,所以不需要更换男朋友,只需要“调教”他努力学习萨克斯,让技艺更加精湛(此为作用2)~~ 当然上述纯属个人做梦哈~ 还是结合上图以及看以下的代码会更加严谨一些~~// 虚函数实现实例,以乐器进行讲述#include<iostream>using namespace std;// 音调enum note{middleC, Csharp, Cflat};// 乐器类,一般分为管乐器、弦乐器、打击乐器class Instrument{public:virtual void play(note) const{cout << "Instrument::play" << endl;}virtual char*what() const{return "Instrument";}virtual void adjust(int){}};// 管乐器,如号class Wind : public Instrument{public:void play(note) const{cout << "Wind::play" << endl;}char* what() const{return "Wind";}void adjust(int){}};// 打击乐器,如鼓,钢琴class Percussion:public Instrument{public:void play(note) const{cout << "Percussion::play" << endl;}char* what() const{return "Percussion";}void adjust(int){}};// 弦乐器,如小提琴class Stringed:public Instrument{public:void play(note) const{cout << "Stringed::play" << endl;}char* what() const{return "Stringed";}void adjust(int){}};// 铜管乐器,如萨克斯class Brass: public Wind{public:void play(note) const{cout << "Brass::play" << endl;}char *what() const {return "Brass";} };// 木管乐器:如笛子class WoodWind: public Wind{public:void play(note) const{cout << "WoodWind::play" << endl;}char *what() const {return "WoodWind";} };// 乐器演奏中C调void tune(Instrument &i){// ...i.play(middleC);}// New function:void f(Instrument& i){i.adjust(1);}// 乐器数组Instrument* A[] = {new Wind,new Percussion,new Stringed,new Brass,};// 实现不同乐器的演奏int main(){Wind flute;Percussion drum;Stringed violin;Brass flugelhorn;WoodWind recorder;tune(flute); // 吹管乐器tune(drum); // 敲打击乐器tune(violin); // 拉弦乐器tune(flugelhorn); // 吹铜管乐器tune(recorder); // 吹木管乐器f(flugelhorn);}/* 运行结果Wind::playPercussion::playStringed::playBrass::playWoodWind::play*/Q3:多态学习(虚函数)的一些误区以前老师告诉我们虚函数就是能够使得基类指针指向派生类对象,从而实现晚绑定,也就是运行时多态。
这句话是片面的。
使用虚函数是为了实现多态。
而具体多态的物理实现方式就是通过基类指针指向派生类对象。
所谓绑定是将函数调用与函数体进行绑定。
在如上的tune函数中,其函数调用与函数体绑定,调用的将是“Instrument::play”。
而实现晚捆绑,当运行时,基类指针指向派生类对象的时候,将会获取其派生类对象中的虚函数表(虚函数表在对象生成时,由构造函数创建),从而调用派生类对象的具体实现。
函数重载也是一种多态,但其是一种静态绑定,而虚函数是使用的是动态绑定。
具体原因我也只能些许意会,难以言传。
Q4: 如何使用虚函数,使用虚函数有哪些注意事项如果想通过虚函数实现多态,要满足以下两个要求:(1)需要有继承派生类继承于父类。
如上例子中,有父类Instrument类,也有派生类Wind 类等。
(2)需要virual关键字只需要在父类的方法中添加virtual关键字其就为虚函数,派生类继承父类得到的该方法即使没有加virtual,其也为虚函数。
如play函数,只要在Instrument 类中加关键字为virtual,在派生类Wind,Stringed等中play函数都没有加virtual,不过其仍然为虚函数。
对于上面的例子我们将进行以下几个更改,大家自己看看会出现什么样的错误。
(1)将Instrument的adjust函数注释掉(2)给Wind,Stringed,Percussion中的adjust函数添加virtual关键字(3)将f(Instrument& i)注释掉,将主函数中的f(flugelhorn)注释掉(4)在主函数的最后中添加代码,A[0]->adjust(1); A[0]为wind对象。
从上面知道,在父类中没有声明的函数,即使在派生类中也是虚函数,用指向派生类对象的基类指针来调用本地虚函数,是会报致命错误的!所以虚函数在派生类实现,但是必须在父类中声明!Q5:纯虚函数和虚析构函数,为什么要引进纯虚函数?为什么有虚析构函数,没有虚构造函数?纯虚函数是指使用关键字vitual,并且在其后面加上0.如在上述Instrument 类中声明void adjust(int)=0。
此adjust即为纯虚函数。
含有纯虚函数的类为抽象类,即此时的Instrument类为抽象类,抽象类不能实例化对象,其派生类必须实现纯虚函数,否则其派生类也将成为抽象类。
为什么需要纯虚函数?对于这个问题,需要引进对象切片的概念。
其实纯虚函数就是为了生成抽象类,防止实现对象实例化,一旦抽象类实例化对象,系统将会报错。
那么实例化对象会出现什么样的错误呢?程序语言中引进某一机制,一般是为了使程序更健壮,不会引起难以预料或是不易发现的错误,或者是为了便于维护和扩展。
当多态地处理对象时,传地址与传值有明显的不同。
所有看到的虚函数的例子都是传地址(指针或引用),而不是传值的(传对象)。
这是因为地址有相同的长度,传递派生类(它通常稍大一些)对象的地址和传递基类(它通常更小一点)对象的地址是相同的。
如前面所述,这是使用多态的目的,即让对基类对象操作的代码也能透明地操作派生类对象。
(这段话虽然拗口,但是会让你有醍醐灌顶的感觉~~)假如我们传值,也就是传对象,这时候将会将派生类对像赋值给基类对象,此时会出现一种很悲剧的状况。
派生类对象被强迫地转为基类对象,此时派生类本身具有的“个性”会被无情的“阉割”掉。
此种现象就称为对象切片。
为了防止悲剧的发生,我们在其萌芽期间,就扼杀掉。
也就是使得基类成为抽象类,其不能实例化对象,此时我们只能使用基类的指针,并通过基类指针指向派生类对象,实现多态。
简而言之,纯虚函数是为了生成抽象类,防止生成对象,防止抽象类实例化对象是为了防止对象切片。
什么是虚析构函数,及其作用和特点是什么?虚析构函数就是指在析构函数前加virtual关键字(有点废话哦~)。