面向对象程序设计的基本特征有哪些

面向对象程序设计的基本特征有哪些,第1张

面向对象的特点是:封装多态继承其中多态有分为重载和重写面向对象的编程思想更加接近现实的事物

有这样几点好处:

1是编程更加容易因为面向对象更接近于现实所以你可以从现实的东西出发进行适当的抽象

2在软件工程上面向对象可以使工程更加模块化实现更低的耦合和更高的内聚

3在设计模式上(似乎只有面向对象才设计到设计模式)面向对象可以更好的实现开-闭原则也使代码更易阅读

程序设计主要方法有面向结构的方法和面向对象的方法。

结构化程序设计

随着计算机的价格不断下降,硬件环境不断改善,运行速度不断提升。程序越写越大,功能越来越强,讲究技巧的程序设计方法已经不能适应需求了。记得是哪本书上讲过,一个软件的开发成本是由:程序设计 30% 和程序维护 70% 构成。这是书上给出的一个理论值,但实际上,从我十几年的工作经验中,我得到的体会是:程序设计占 10%,而维护要占 90%。也许我说的还是太保守了,维护的成本还应该再提高。下面这个程序,提供了两种设计方案,大家看看哪个更好一些那?

题目:对一个数组中的100个元素,从小到大排序并显示输出。(BASIC)

方法1:冒泡法排序,同时输出。

FOR I=1 TO 100

  FOR J=I+1 TO 100

IF A[I] > A[J] THEN T=A[J]: A[J]=A[I]: A[I]=T

  NEXT J

  A[I]

NEXT I

方法2:冒泡法排序,然后再输出。

FOR I=1 TO 100

FOR J=I+1 TO 100

IF A[I] > A[J] THEN T=A[J]: A[J]=A[I]: A[I]=T

NEXT

NEXT

FOR I=1 TO 100

A[I]

NEXT

显然,“方法1”比“方法2”的效率要高,运行的更快。但是,从现在的程序设计角度来看,“方法2”更高级。原因很简单:(1)功能模块分割清晰——易读;(2)也是最重要的——易维护。程序在设计阶段的时候,就要考虑以后的维护问题。比如现在是实现了在屏幕上的输出,也许将来某一天,你要修改程序,输出到打印机上、输出到绘图仪上;也许将来某一天,你学习了一个新的高级的排序方法,由“冒泡法”改进为“快速排序”、“堆排序”。那么在“方法2”的基础上进行修改,是不是就更简单了,更容易了?!这种把功能模块分离的程序设计方法,就叫“结构化程序设计”。

面向对象的程序设计

随着程序的设计的复杂性增加,结构化程序设计方法又不够用了。不够用的根本原因是“代码重用”的时候不方便。面向对象的方法诞生了,它通过继承来实现比较完善的代码重用功能。很多学生在应聘工作,面试的时候,常被问及一个问题“你来谈谈什么是面向对象的程序设计”,学生无言,回来问我,这个问题应该怎么回答。我告诉他,你只要说一句话就够了“面向对象程序设计是对数据的封装;范式(模板)的程序设计是对算法的封装。”后来再有学生遇到了这个问题,只简单的一句对答,对方就对这个学生就刮目相看了(学生后来自豪地告诉我的)。为什么那?因为只有经过彻底的体会和实践才能提炼出这个精华。

面向对象的设计方法和思想,其实早在70年代初就已经被提出来了。其目的就是:强制程序必须通过函数的方式来 *** 纵数据。这样实现了数据的封装,就避免了以前设计方法中的,任何代码都可以随便 *** 作数据而因起的BUG,而查找修改这个BUG是非常困难的。那么你可以说,即使我不使用面向对象,当我想访问某个数据的时候,我就通过调用函数访问不就可以了吗?是的,的确可以,但并不是强制的。人都有惰性,当我想对 i 加1的时候,干吗非要调用函数呀?算了,直接i++多省事呀。呵呵,正式由于这个懒惰,当程序出BUG的时候,可就不好捉啦。而面向对象是强制性的,从编译阶段就解决了你懒惰的问题。

巧合的是,面向对象的思想,其实和我们的日常生活中处理问题是吻合的。举例来说,我打算丢掉一个茶杯,怎么扔那?太简单了,拿起茶杯,走到垃圾桶,扔!注意分析这个过程,我们是先选一个“对象”------茶杯,然后向这个对象施加一个动作——扔。每个对象所能施加在它上面的动作是有一定限制的:茶杯,可以被扔,可以被砸,可以用来喝水,可以敲它发出声音;一张纸,可以被写字,可以撕,可以烧。也就是说,一旦确定了一个对象,则方法也就跟着确定了。我们的日常生活就是如此。但是,大家回想一下我们程序设计和对计算机的 *** 作,却不是这样的。拿DOS的 *** 作来说,我要删除一个文件,方法是在DOS提示符下:c:> del 文件名<回车>。注意看这个过程,动作在前(del),对象在后(文件名),和面向对象的方法正好顺序相反。那么只是一个顺序的问题,会带来什么影响那?呵呵,大家一定看到过这个现象:File not found “啊~~~,我错了,我错了,文件名敲错了一个字母”,于是重新输入:c:> del 文件名2<回车>。不幸又发生了,计算机报告:File read only 哈哈,痛苦吧:)。所以DOS的 *** 作其实是违反我们日常生活中的习惯的(当然,以前谁也没有提出过异议),而现在由于使用了面向对象的设计,那么这些问题,就在编译的时候解决了,而不是在运行的时候。objfun(),对于这条语句,无论是对象,还是函数,如果你输入有问题,那么都会在编译的时候报告出来,方便你修改,而不是在执行的时候出错,害的你到处去捉虫子。

同时,面向对象又能解决代码重用的问题——继承。我以前写了一个“狗”的类,属性有(变量):有毛、4条腿、有翘着的尾巴(耷拉着尾巴的那是狼)、鼻子很灵敏、喜欢吃肉骨头方法有(函数):能跑、能闻、汪汪叫如果它去抓耗子,人家叫它“多管闲事”。好了,狗这个类写好了。但在我实际的生活中,我家养的这条狗和我以前写的这个“狗类”非常相似,只有一点点的不同,就是我的这条狗,它是:卷毛而且长长的,鼻子小,嘴小。于是,我派生一个新的类型,叫“哈巴狗类”在“狗类”的基础上,加上新的特性。好了,程序写完了,并且是重用了以前的正确的代码——这就是面向对象程序设计的好处。我的成功只是站在了巨人的肩膀上。当然,如果你使用VC的话,重用最多的代码就是MFC的类库。

面向对象程序设计有4个主要特点,分别是:抽象、封装、继承、多态。以下是具体解释;

一、抽象和封装

类和对象体现了抽象和封装

抽象就是解释类与对象之间关系的词。类与对象之间的关系就是抽象的关系。一句话来说明:类是对象的抽象,而对象则是类得特例,即类的具体表现形式。

封装两个方面的含义:一是将有关数据和 *** 作代码封装在对象当中,形成一个基本单位,各个对象之间相对独立互不干扰。二是将对象中某些属性和 *** 作私有化,已达到数据和 *** 作信息隐蔽,有利于数据安全,防止无关人员修改。把一部分或全部属性和部分功能(函数)对外界屏蔽,就是从外界(类的大括号之外)看不到,不可知,这就是封装的意义。

二、继承

面向对象的继承是为了软件重用,简单理解就是代码复用,把重复使用的代码精简掉的一种手段。如何精简,当一个类中已经有了相应的属性和 *** 作的代码,而另一个类当中也需要写重复的代码,那么就用继承方法,把前面的类当成父类,后面的类当成子类,子类继承父类,理所当然。就用一个关键字extends就完成了代码的复用。

三、多态

没有继承就没有多态,继承是多态的前提。虽然继承自同一父类,但是相应的 *** 作却各不相同,这叫多态。由继承而产生的不同的派生类,其对象对同一消息会做出不同的响应。

面向对象三大特性:封装,继承,多态

面向对象(Object Oriented,缩写为OO)是现代软件技术的精髓。从早期的SmallTalk到如日中天的Java,都渗透着面向对象思想。

OO具有三大特性:封装性、继承性和多态性。想掌握面向对象思想,就必须深入理解

其三大特性。这里我尽量少谈概念,只用一个生活中的例子和一段代码来解释它们。

1、封装性(Encapsulation)

所谓封装,就是将某些东西包装和隐藏起来,让外界无法直接使用,只能通过某些特定的方式才能访问。OO将万物都视为“对象”(Object),任何对象都具有特性和行为。我们将其特性称为“成员变量” (MemberVarible),将其行为称之为“成员函数"(Member Function),被封装的特性只能通过特定的行为去访问。

大家都见过旅馆里常用的一种茶叶吧,就是用纸袋把茶叶包装起来再系是一根线。用的时候只需要将其放在水杯里泡就行。这样的好处是不会将茶叶渣和茶垢弄的满杯子都是。

好!这就是一个封装的例子。

我们喝茶的目的是享受茶叶的香冽;所以茶叶的味道(Flavour)就是茶叶所具有的最

重要特性之一;可是我们无法直接享受它的清香,因为被外面的纸袋“封装”起来了。唯一的办法就是“泡”(Dilute),将茶袋扔在开水中泡,它的味道就出来了,融入水中。

如果我们把袋装茶叶看作一个对象的话,它提供了成员变量Flavour和成员函数Dilute

。并且Flavour是私有(Private)的,我们不能直接把它吞进肚子去,而只能通过成员函

数Dilute才能享受Flavour。

下面用C++代码来描述这个例子:

Class CTea

{

Private:

Cstring m_Flavour; //味道

Cstring m_Color; //颜色

//等等其它属性

Private:

Void CTea(); //构造函数

Void ~CTea(); //析构函数

Public:

Cstring Dilute();//沏茶

//等等其它方法

}

Cstring CTea::Dilute()

{

//怎样泡出味道来的代码

}

这就是封装。通过将对象的某些属性声明为Private隐藏起来,只能使用其提供的特定

方法去访问。

2、继承(Inheritance)

如果只是封装,那么非面向对象语言也能部分的做到。比如在C中,用结构(Struct)、

VB中用自定义类型(Type)也能封装一些变量。

OO最有吸引力的特性是继承。通俗的说后代具有祖先的某些特点就叫继承,当然后代还可以具有自己独有的特征。举个例子吧,菜刀。

菜刀(cutlery)是钢(Steel)做的,钢是一种金属(Metal),金属则是大千世界里的一种物质(Substance)。所以菜刀的一些特性可以追溯到物质具有的一般属性。正是因为这个道理,MFC中所有类均从CObject继承而来。

这就是继承。菜刀直接继承了钢的特性,钢又继承了金属的特性,下面的代码描

述了这种复杂而有独特的继承关系:

Class CSubstance

{

Private:

int m_color;

void CSubstance();

void ~CSubstance();

//(我是学文科的,具体属性说不上来)

}

Class CMetal:Public CSubstance

{

void CMetal();

void ~CMetal();

//

}

Class CSteel:Public CMetal

{

void CSteel();

void ~CSteel();

//

}

Class CCutlery:Public CSteel

{

private:

Cstring m_Blade;

void CCutlery();

void ~CCutlery();

//

Public:

void Cut();

}

这里,CSubstance被称为基类(Base class),其它被称为衍生类(Derived class)。衍生类与基类是“Is kind of”的关系。子类与其祖先类之间复杂的函数调用关系不在本文讨论之列。

继承是一种树状的层次关系。子类在继承祖先类的成员变量和成员函数的同时也可以

定义自己的成员变量和成员函数。比如,Metal 除了继承了Substance的一般特性外,还具有自己的属性诸如可延展性;CCutlery在继承CSteel的特性后还具有自己的成员诸如“刀刃”(Blade)、“锋利”(Sharpness)、行为有如“切”(Cut)等。

面向对象技术是对现实生活的抽象,你可以用生活中的经验去思考程序设计的逻辑。

3、多态性(Polymorphism)

讨论多态之前先要明白什么是“虚拟”(Virtual)。C++/MFC就是用虚拟这种方式实现多态的。为什么“虚拟”这个概念?看下边的例子:

Class Cincect //昆虫类

{

private:

int m_foot; //脚的数量

//其它成员变量

private:

void Cincect();

void ~Cincect();

public:

void Bite()//咬人

{

//怎样咬人的代码,比如张开嘴啃

}

}

我把Bite(咬)这个动作在基类中定义为一般化动作。可是,不是所有昆虫咬

人的方法都一样(况且还有的根本就不咬人呢,比如蜻蜓),比如蚊子是用嘴那个

吸管叮人而蚂蚁是用嘴去夹。

从昆虫这个类别衍生出以下两个类别:Cant(蚂蚁)、Cmosquito(蚊子)。

class Cant :public Cincect //蚂蚁类

{

}

class Cmosquito :public Cincect //蚊子类

{

}

它们都继承了Cincect的所有成员,当然也继承了Bite()这个动作。现在就有问题了:

同样继承自昆虫,当我们使用Bite()这个动作时怎么才能区分蚂蚁和蚊子各自的独有的咬人方式呢?

方法之一是用“::”符号指明具体引用的是那一个,但这样明显失去了灵活性;

另一种方法就是“虚拟”。使用关键字virtual将Bite()声明为虚拟函数,然后在每个

衍生类中重新定义,描述它们各自的咬人方法,调用的时候也不会都一种结果啦。于是上边的例子可以改写为:

Class Cincect //昆虫类

{

private:

int m_foot; //脚的数量

//其它成员变量

private:

void Cincect();

void ~Cincect();

public:

virtual Bite(){}//咬人,但我们只声明这个成员函数,

//却让它什么动作都不做,让衍生类自己去定

//义各自的咬人方法

}

class Cant :public Cincect //蚂蚁类

{

virtual Bite();

}

Cant::Bite()

{

//蚂蚁具体的咬人方式

}

class Cmosquito :public Cincect //蚊子类

{

virtual Bite();

}

Cmosquito::Bite()

{

//蚊子具体的咬人方式

}

所以,虚拟的目的是只在基类中将一般化动作声明一个成员函数的原型而不做

具体定义,让衍生类自己去定义。

这就是面向对象的特征之三:多态性。基类的同一个成员在不同的衍生类中可以具

有不同的形态,更好地抽象和描述大千世界中的诸多“对象”。

1了解什么是多态性

2如何定义一个虚方法

3如何重载一个虚方法

4如何在程序中运用多态性

面向对象程序设计中的另外一个重要概念是多态性。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。 如果这些对象都有同名方法,就可以调用每个对象的同名方法。本节课将向你介绍如何完成这些事情。

1清单9-1 带有虚方法的基类:DrawingObjectcs

using System;

public class DrawingObject

{

public virtual void Draw()

{

ConsoleWriteLine("I'm just a generic drawing object");

}

}

说明

清单9-1 定义了DrawingObject类。这是个可以让其他对象继承的基类。该类有一个名为Draw()的方法。Draw()方法带有一个virtual修饰符,该修饰符表明:该基类的派生类可以重载该方法。DrawingObject类的 Draw()方法完成如下事情:输出语句"I'm just a generic drawing object"到控制台。

2清单9-2 带有重载方法的派生类:Linecs, Circlecs, and Squarecs

using System;

public class Line : DrawingObject

{

public override void Draw()

{

ConsoleWriteLine("I'm a Line");

}

}

public class Circle : DrawingObject

{

public override void Draw()

{

ConsoleWriteLine("I'm a Circle");

}

}

public class Square : DrawingObject

{

public override void Draw()

{

ConsoleWriteLine("I'm a Square");

}

}

说明

清单9-2定义了三个类。这三个类都派生自DrawingObject类。每个类都有一个同名Draw()方法,这些Draw()方法中的每一个都有一个重载修饰符。重载修饰符可让该方法在运行时重载其基类的虚方法,实现这个功能的条件是:通过基类类型的指针变量来引用该类。

3清单9-3 实现多态性的程序:DrawDemocs

using System;

public class DrawDemo

{

public static int Main(string[] args)

{

DrawingObject[] dObj = new DrawingObject[4];

dObj[0] = new Line();

dObj[1] = new Circle();

dObj[2] = new Square();

dObj[3] = new DrawingObject();

foreach (DrawingObject drawObj in dObj)

{

drawObjDraw();

}

return 0;

}

}

说明

清单9-3演示了多态性的实现,该程序使用了在清单 9-1 和清单9-2中定义的类。在DrawDemo类中的Main()方法中,创建了一个数组, 数组元素是DrawingObject 类的对象。该数组名为dObj,是由四个DrawingObject类型的对象组成。

接下来, 初始化dObj数组, 由于Line, Circle和Square类都是DrawingObject类的派生类,所以这些类可以作为dObj数组元素的类型。 如果C#没有这种功能,你得为每个类创建一个数组。继承的性质可以让派生对象当作基类成员一样用,这样就节省了编程工作量。

一旦数组初始化之后,接着是执行foreach循环,寻找数组中的每个元素。在每次循环中, dObj 数组的每个元素(对象)调用其Draw()方法。多态性体现在:在运行时,各自调用每个对象的Draw()方法。尽管dObj 数组中的引用对象类型是DrawingObject,这并不影响派生类重载DrawingObject 类的虚方法Draw()。 在dObj 数组中,通过指向DrawingObject 基类的指针来调用派生类中的重载的Draw()方法。

输出结果是:

I'm a Line

I'm a Circle

I'm a Square

I'm just a generic drawing object

在DrawDemo 程序中,调用了每个派生类的重载的Draw()方法。 最后一行中,执行的是DrawingObject类的虚方法Draw()。这是因为运行到最后,数组的第四个元素是DrawingObject类的对象。

小结

现在对多态性有所了解之后,你可以在派生类中,实现一个重载基类虚方法的方法。虚方法和重载的派生类方法之间的关系就体现出C#的多态性。

以上就是关于面向对象程序设计的基本特征有哪些全部的内容,包括:面向对象程序设计的基本特征有哪些、面向对象程序设计主要有哪些方法、面向对象程序设计具有哪些特性呢等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9293002.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-26
下一篇2023-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存