面向过程程序和面向对象程序有什么区别?

32

我对编程还比较新,但在StackOverflow上看到了一些有趣的关于不同编程方法的讨论。我仍然不太清楚过程式编程和面向对象编程之间的区别。听起来面向对象编程仍然使用过程(方法),但一切都以对象为中心组织。但似乎过程仍然可以让您做同样的事情。就像在C语言中,您可以将所有类似的过程放入库中。那么你不是可以说C语言中的库与C++中的对象类似吗?


参见这个旧的SO问题 - jogojapan
1
可以考虑将其转移到程序员SO。 - Kromster
17个回答

36
在过程式编程中,代码是最重要的,数据则是从属的。换句话说,你有一些操作数据的程序,它们通常并没有紧密绑定。
在面向对象的世界中,对象是最重要的事物。一个对象由数据和可以操作该数据的代码组成,它们之间紧密绑定。这就是封装的概念,隐藏信息。
举个例子,假设你有一个数字,想把它翻倍。采用过程式编程的方式是:
n = n * 2

这段代码很明确地将n乘以2,并将结果存回n。

采用面向对象的方式,可以向数字对象发送一个“消息”,告诉它将自己翻倍:

n.double();
这种优势被称为多态性。假设您决定想要将字符串“bob”加倍,那会发生什么呢?在面向过程的世界中,您将不得不提供更多的代码来执行加倍操作,同时还必须以不同的方式调用该代码。
采用面向对象方法,您可以创建一个字符串对象,该对象还可以接收“double”消息。将字符串加倍的代码属于字符串对象,因此它知道必须对数字对象采取不同的行动。如果它决定让“bob”* 2变成“bobbob”,则代码看起来会像这样:
class number:                    class string:
    int n                           char array s
    procedure double:               procedure double:
        n = n * 2                       s = string_join(s,s)
那么,无论x是什么类型(数字或字符串),您都可以调用x.double(),它会知道要运行哪些代码-这大大简化了您的代码。您可以对整数、字符串、矩阵、复数、实数、显示器上的窗口大小以及各种不同的东西进行加倍。
而且你是对的,C库可以看起来有点像对象。经典示例是stdio.h-您永远不关心FILE*实际指向的是什么,只关心它将以某种方式运行。 FILE*fopen()fclose()和其他函数是一种表示C的I / O功能的类。

非常好的解释。我很惊讶这被选为最佳答案。我认为这真的很到位。 - Willem Obst
问题:我理解您的示例如何表示多态的概念,但我不确定它如何表示封装 - 是因为双重功能现在被包装在一个名为方法的小模块化功能中吗?一旦我们有了一个方法,我们就有了封装吗? - Willem Obst
1
@WO,封装是数据或代码的隐藏。代码封装是允许多态性的原因,因为代码现在属于对象而不是外部代码作用于对象。你告诉对象要做什么,而不是如何做。它知道如何做。封装/多态性密切相关。 - paxdiablo
@Willem,我想你的意思是“...惊讶这个没有被选中...”。谢谢,但这就是SO的变幻莫测。提问者决定接受的答案,社区决定最佳答案。你和我都知道我的回答是最好的 :-) 但我们只是两个人(而且我不能给它点赞)。 - paxdiablo
1
这真的是一份很好的解释。我认为这将对我的许多朋友在面向对象编程入门课程中有所帮助。我会与他们分享。感谢您抽出时间分享。 :D - Mike Grace

21

大多数面向对象的编程语言都可以进行过程式编程,但是面向对象的强大之处在于其具有继承、封装和抽象过程逻辑的能力。 我认为你是正确的,一个库应该与类非常相似。它应该有自己的作用域,并通过具有有意义名称的函数来封装逻辑。


4
为了补充您的回答,继承、封装和多态是面向对象编程的三大支柱。 - Marco Luglio

15

你的观察是正确的,面向对象程序在很多方面都基于过程式编程范例。你也正确地指出,语法上实际上只是调用函数。实际上,你可以使用过程式机制来实现许多面向对象语言的特性(例如,在C ++中使用函数指针)。因此,您可以进行面向对象设计,仍然可以在过程式语言中实现它(例如,像旧版C ++编译器一样)。

面向对象范式的重要性不在于语言机制,而在于思考和设计过程。在过程式编程中,思考的重点是操作,通过其他操作将这些操作分解、分组成模块等。这意味着数据或状态处于次要重要性。就像考虑数学运算一样。

另一方面,面向对象范式认为您需要将状态和操作作为一个实体考虑,并设计您的程序作为实体之间交换状态和激活操作的交互。


13

两者之间的区别微妙但显著。

在过程式程序中,模块通过读取和写入存储在共享数据结构中的状态来相互交互。

而在面向对象的程序中,以对象形式存在的模块通过向其他对象发送消息来相互交互。


1
我有一个疑问。Java是一种过程式语言吗? - Raja Anbazhagan

10

依我之见,面向对象编程是一个比过程式编程更高层次的概念。这两者并不是互斥的,因为OO程序中的单个方法看起来与过程式程序中的单个函数几乎相同。这与函数式编程形成对比,后者需要完全不同的思维方式。此外,您可以通过使所有内容都是静态的等方式在OO语言中以过程式风格进行编写。您可以成为人工编译器,并通过使用大量的函数指针和结构体指针转换在C中有效地编写OO代码。

因此,OO更像是一种设计哲学和世界观,而不是具有严格定义的东西。它要求继承、多态等作为主要模式来构建代码的架构,并提供语法以使这些模式表达得到,而不用采用低级技巧。它要求您将作用于一组数据状态的代码视为该数据的属性,而不是存在于自身的过程。这并不是非黑即白的。根据您如何依赖继承、多态、类以及“方法作为数据属性”的世界观来构造、解释和理解您的代码,您的代码可以是“更”或“少”OO。


关于面向对象代码与过程式代码以及面向对象语言与过程式语言之间的区别,你提出了很好的观点。点赞。 - Eduard - Gabriel Munteanu

9
OO主要是一种思维方式。如果你真的想,你可以在C语言中编写OO程序,而且你可以在C++/Java中完全使用过程化代码;我的意思是,即使你在表面上使用类,它仍然可能是过程化的。
OO背后的理念是状态抽象。你不再“以数据分组”的方式来思考,而是以“对象”为基础思考,其中一个对象是“数据分组和操作这些数据的方式”的“接口”。
这听起来都很哲学,因为它确实如此。
这里有很多要说的,但在一个小的SO帖子中无法全部说清楚,所以我就在这里了。
更新 正如Flanagan's answer中提到的那样,OO语言实现了利用这种抽象的结构。
我的意思是,你可以在结构体、函数和函数指针方面技术性地“黑掉”类和多态性。

这是一个C中的OO的示例


8

程序处理数据 - 输入数据,应用一些处理,得到输出数据

有时,一些数据元素与其他数据元素相关,将它们方便地组合成一个 数据结构,可以将其作为单个单元进行操作和寻址。

现在我们的过程可以将数据结构作为输入并更改它和/或生成另一个数据结构作为输出。

有时我们注意到一些过程仅关注某种类型的数据结构;将这些过程与其数据结构分组在一起,称为 对象,这很方便。

创建对象的模板称为; 对象被称为类的实例

我们可能会注意到一类非常像另一类,因此我们不复制和粘贴代码,让一个类从另一个类继承:子类继承自父类或“基类”。通过这种方式,子类可以访问超类的所有数据结构和过程,并以某种方式增强或覆盖它们

如果我们礼貌地请求对象为我们做某事而不是直接调用其过程,这称为消息传递,即使没有实际的“消息”传递。乐趣在于,许多不同类型的对象可以理解相同的消息,这导致了多态的概念。例如,我们可以要求许多不同类型的文档打印自己,并且它们都会适当地响应。

支持通过类或其他方式具有消息传递和继承的对象的语言称为面向对象。如果没有继承,则该语言仅为基于对象

祝你学习顺利!


4
太棒了!无法想象如果你没有疲惫会是什么样子。我会保存这个的。 - Willem Obst
@[Willem Obst]:谢谢 - 如果我有更多时间,它会更短的;-) - Steven A. Lowe
4
哇!我希望我的老师能像你一样清晰地讲解东西。感谢你的贡献! - Mike Grace
[@Mike Grace]: 谢谢你的高度赞赏。我据说正在写一本书 ;-) http://stackoverflow.com/questions/303276/suggest-chapters-topics-for-oop-book - Steven A. Lowe

6

不同之处在于对象具有程序和相关数据在同一位置 - 过程化语言使用“结构体”(将相关数据组合在一起的东西),这使得数据与程序分开。实际上,您在面向对象语言中所做的任何事情都应该可以在过程化语言中通过结构体和过程的组合来实现。

主要区别在于面向对象语言使程序员采用了不同的思维方式。


4

“Procedural”是面向过程/函数/逻辑(或逻辑导向)区分中的一部分 (可与c、lisp和prolog比较),代表不同描述程序执行方式的方法。

面向对象编程则是独立于前述概念的,它描述的是将子程序及其数据进行分类的方法。C++ 和 Java 是带有面向对象特性的面向过程语言;而Fortran 77 是没有面向对象特性的面向过程语言。Common Lisp ��持面向对象编程,但一些旧版Lisp则不支持。原始的Prolog不支持对象,而我也不知道有哪个逻辑导向的语言支持(我不擅长逻辑导向编程,如果有大量空闲时间的话,我会把这项任务放在我的ToDoList里。我几乎没做过函数式编程)。

正如其他人所指出的,正确的面向对象编程思维方式改变了你的编程方式,这与从面向过程到函数式编程的转换一样重要。


顺便说一下——我经常看到“面向过程”一词用来区分非面向对象的面向过程语言和它们的面向对象版本,但我认为这是一个不好的用法,因为没有一个干净的形容词可以表示“非面向对象”的概念。不同的人可能有不同看法。


你是说用“逻辑”这个词来避免像“我无法命名一种逻辑语言…”这样的灾难?是的,我能理解。 - dmckee --- ex-moderator kitten

2
更容易理解上下文,看看语言之间介绍的其他抽象概念。
汇编语言和过程式语言(如C或Pascal)之间的一个关键区别是引入了“过程”抽象。编写汇编代码的人会创建过程,但这很困难且容易出错,而过程式语言为您提供了使其更容易的工具。
过程式语言和面向对象语言(如C++)之间的区别在于“对象”抽象。编写C的人经常创建概念对象{{link1:但这很困难且容易出错},而面向对象的语言为您提供了使其更容易的工具。
像微软的Sing#(或Erlang)这样的东西将消息/进程抽象引入了语言中。当然,您可以在汇编、C或C++中进行消息传递和进程创建,但Sing#使它更容易。
所有这些都归结为相同的机器代码,这些抽象仅是为了使我们的大脑更好地理解,而不是为了计算机。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接