31

我对编程还很陌生,但我一直在阅读有关 StackOverflow 的一些关于各种编程方法的有趣讨论。我仍然不是 100% 清楚过程编程和面向对象编程之间的区别。听起来面向对象编程仍然使用过程(方法),但一切的组织方式都不同,因为对象是节目的主角。但在我看来,程序仍然允许你做所有相同的事情。就像在 C 中一样,您可以将所有类似的过程放入一个库中。所以你真的不能说 C 中的库类似于 C++ 中的对象吗?

4

17 回答 17

36

在程序化程序中,代码为王,数据为从属。换句话说,您有对数据起作用的程序,它们通常没有紧密绑定。

在 OO 世界中,对象是最重要的东西。一个对象由数据允许作用于该数据的代码组成,它们之间的联系非常紧密。它是封装的概念,信息的隐藏。

举个例子,假设你有一个数字,你想把它加倍。这样做的程序方法是:

n = n * 2

这里的代码非常明确地将 n 乘以 2 并将结果存储回 n。

这样做的 OO 方法是向 number 对象发送一条“消息”,告诉它自己加倍:

n.double();

这样做的优点称为多态性。当您决定要能够将“bob”之类的字符串加倍时会发生什么。在程序世界中,您必须提供更多代码来进行加倍,但您还必须以不同的方式调用该代码。

使用 OO,您可以创建一个字符串对象,该对象也可以接收“双重”消息。将字符串加倍的代码属于字符串对象,因此它知道它必须与数字对象不同。如果它决定 "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——你从来不关心a实际指向什么FILE*,只关心它会以某种方式运行。、FILE*和其他函数fopen()fclose()代表 C 的 I/O 能力的一类。

于 2009-02-10T01:35:00.853 回答
21

您可以在大多数 OO 语言中进行程序化编程,但 OO 的力量来自于继承、封装和抽象该过程逻辑的能力。我认为你是对的,图书馆应该看起来很像一个类。它应该有自己的范围并用有意义的名称封装函数背后的逻辑。

于 2009-02-10T01:13:36.690 回答
15

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

面向对象范式的重要性并不在于语言机制,而是在于思维和设计过程。在过程式编程中,思维是关于操作并使用其他操作分解这些操作,将它们分组为模块等。这意味着数据或状态属于次要的重要性。这就像思考数学运算。

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

于 2009-02-10T02:53:26.810 回答
13

两者之间的差异是微妙的,但意义重大。

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

在面向对象的程序中,对象形式的模块通过向其他对象发送消息进行交互。

于 2009-02-10T06:51:12.980 回答
10

恕我直言,面向对象编程是一个存在于比过程编程更高抽象级别的概念。这两者并不相互排斥,因为 OO 程序中的各个方法看起来与过程程序中的各个函数几乎相同。这与例如函数式编程形成鲜明对比,后者需要完全不同的思维方式。此外,您可以通过将所有内容设为静态等来使用 OO 语言进行程序化编写。您可以成为人类编译器,并通过使用大量函数指针和结构指针转换在 C 中有效地编写 OO 代码。

因此,OO 更像是一种设计哲学和世界观,而不是具有严格定义的东西。它要求将继承、多态等用作构建代码的主要模式,并提供语法以使这些可表达而无需求助于低级技巧。它要求您将作用于数据集合状态的代码视为数据的属性,而不是自身存在的过程。它不是黑白的。您的代码可以是“更多”或“更少”OO,具体取决于您对继承、多态性、类和“作为数据属性的方法”的世界观作为结构化和解释/理解代码的手段的依赖程度。

于 2009-02-10T01:45:44.163 回答
8

OO主要是一种思维定势。你可以用 C 编写面向对象(如果你真的想……),你可以完美地用 C++/Java 编写程序代码;我的意思是,即使你在表面上使用类,它仍然可以是程序性的。

OO 背后的思想是状态的抽象。不是根据“数据分组”来“思考”,而是根据“对象”来“思考”,其中对象是“数据分组和操作这些数据的方法”的“接口”。

这一切听起来很哲学,因为它是

这里有很多要说的,在一个小的SO帖子中不能全部说完,所以我就放在这里了。

更新
正如Flanagan 的回答中提到的,OO 语言实现了利用这种抽象的结构。

我的意思是,从技术上讲,您可以在结构、函数和函数指针方面“破解”类和多态性。

这是C 中的 OO示例

于 2009-02-10T01:42:16.777 回答
7

[原谅初级风格,来晚了,我累了]

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

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

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

偶尔我们会注意到一些程序只关心某种数据结构;将这些过程与它们的数据结构组合在一起很方便,称之为对象

用于创建对象的模板称为;一个对象被称为一个类的一个实例

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

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

通过消息传递和继承支持对象(通过或不通过类)的语言称为面向对象。如果没有继承,语言只是基于对象的

祝你学习顺利!

于 2009-02-10T02:35:36.090 回答
6

不同之处在于对象在同一位置具有过程和相关数据 - 过程语言使用“结构”(将相关数据保存在一起的东西)将数据与过程分开。实际上,您在 OO 语言中所做的任何事情都应该在结合了结构和过程的过程语言中成为可能。

主要区别在于 OO 语言赋予程序员的思维定势。

于 2009-02-10T01:12:19.173 回答
4

过程是描述程序应该做什么的不同方式之间的过程/功能/逻辑(或面向逻辑)区别(比较c,lisp和prolog)的一部分。

面向对象与另一个想法正交,并描述了一种将子程序与数据分组的方法。C++ 和 java 是具有面向对象特性的过程语言;fortran77 是一种没有面向对象特性的过程语言。Common lisp 支持面向对象;一些较旧的 lisps 没有。普通的 prolog 不支持对象,而且我无法命名一种面向逻辑的语言(我不做面向逻辑的编程,当我大量空闲时间时,它在我要做的事情清单上。我几乎不做函数式编程)。

然而,正如其他人所指出的那样,正确的面向对象思维会改变您进行编程的方式,就像从过程式转换到函数式一样。


顺便说一句 - 我看到“过程”用于区分非面向对象的过程语言与其面向对象的兄弟,但我认为这是一个糟糕的用法,因为“不面向对象”缺乏一个干净的形容词。YMMV。

于 2009-02-10T01:19:12.323 回答
2

在上下文中更容易理解,请查看语言之间引入的其他抽象。

汇编语言和像 C 或 Pascal 这样的过程语言之间的一个关键区别是引入了“过程”抽象。编写汇编代码的人会创建程序,但它很难且容易出错,程序语言为您提供了使其更容易的工具。

过程语言和像 C++ 这样的面向对象语言之间的区别在于“对象”抽象。编写“c”的人经常创建概念对象,但它很困难且容易出错,OO 语言为您提供了使其更容易的工具。

来自 Microsoft(或 Erlang)的Sing#之类的东西将 Message/Process 抽象添加到语言中。当然,您可以在程序集、C 或 C++ 中进行消息传递和进程创建,但 Sing# 更容易。

这一切都归结为相同的机器代码,这些抽象纯粹是为了我们的大脑,而不是计算机。

于 2009-02-10T02:48:46.463 回答
2

在程序化程序中,您将一个大问题分解为小问题,并将这些小问题中的每一个抽象为一个过程。这称为过程抽象。

在面向对象的程序中,您将问题分析为一些对象,以及对象之间的交互。这称为对象抽象。

于 2012-03-04T11:01:58.300 回答
2

不同的是

面向过程的编程 - 重视算法而不是数据。这种编程方式集中于过程,即执行特定任务和共享其数据结构的方法。它遵循自上而下的结构。

示例:帕斯卡和 C

面向对象编程 - 重视数据而不是算法。它遵循自下而上的结构。每件事都被视为一个对象。每个对象都有自己的数据结构和过程。它包括数据隐藏、多态性、封装和消息传递等特性。用户在他们的程序中使用它们时,真的不必理会这些对象内部的内容。

示例:C++ 和 Java

于 2013-02-09T07:42:39.567 回答
1

这是一个简化的答案。

  • 在真正的 OO 语言中,唯一的过程编码是在对象内部完成的。

  • C 没有对象,而 C++ 是一种支持对象的语言。另一方面,Java 一切都是对象(原语除外)。一切都是打字的。

  • 线性进展发生在对象内部,但对象本身只是代码和数据的集合。
于 2009-02-10T01:12:31.827 回答
1

这取决于您如何定义 OOP。就您在对象上调用方法的类 Java OOP 而言,过程编程几乎相同。据我所知,您可以在像 C 这样的过程语言中模拟所有 OOP 原则(封装、抽象、多态性、继承)。证明是GObject,在某种程度上扩展了 Objective-C,以及许多其他使用 C 的 OOP 语言实现,像 cPython。这是通过使用结构并使用函数对这些结构进行操作来完成的:

typedef struct {
    Object *isa;
    String *name;
    Date *birthday;
} Person;

Person *Person_new();
String *Person_name(Person *self);
void Person_setName(Person *self, String *newName);
// ...

界面非常像OOP。它实际上不允许多态性,但它也是可能的。它与 Python 接口非常相似,只是属性与“方法”是分开的:

class Person(object):
    def __init__(self):
        self._name = ""
        self._age = datetime.datetime.now()

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

我选择 Python 作为示例是因为“self”是显式的,就像在 C 示例中一样。许多 OOP 语言,如 Java,都抽象了这一点。

还有类似于 Smalltalk 的 OOP,其中消息被发送到对象,而不是调用对象上的方法。乍一看,差异很微妙,但它提供了很多功能和灵活性。正如 Objective-C 所证明的,这也可以在过程语言中实现。

面向对象编程不一定是一种语言,而是一种范式。Java、Python、Ruby等面向对象的语言提供语法糖来方便地操作对象,这是“过程语言”和“面向对象语言”的主要区别。

事实上,一个库,或者更确切地说是一组在结构上运行的函数,与 C++ 中的对象相同。事实上,C++ 就是以这种方式实现的。

于 2009-02-10T05:07:45.647 回答
0

这里已经提到了很多有趣的点。

一种思考方式是,在 OO 中,您有“对象”的概念,即具有它们固有的特征和行为的事物。它们通常具有某种公共“接口”,它提供了一种机制来检索有关它们的某些信息,但是对象本身,或者更确切地说它的“类”,限制了哪些信息是公开可用的。对象的内部不会暴露给公众,因为通常不需要知道对象“引擎盖下”的肮脏细节。所以面向对象的程序利用了这个结构,以及其他的东西。

过程式编程通常不会利用这种将数据和行为耦合到“对象”中的方式。我以前在 C 中看到过它,但它并不漂亮,而且涉及太多的猴子业务,无法估计一个人可以用 C++ 做些什么。

面向对象开发背后的一个想法是,我不应该通过您提供的方式以外的任何方式来处理您的数据。如果你只为我提供一个经过深思熟虑的界面,你可以让我诚实。现在,如果您使用的是程序方法,并且您向我发送了一个没有内置保护的结构,那么我可以为所欲为,如果我是愚蠢或邪恶的,我可以更改您可能不希望我做的事情改变。

当然,如果你很聪明,你可以绕过这个对象,但你必须不遗余力地做到这一点。

这并不完整,但这是一方面。

于 2009-02-10T01:42:26.200 回答
0

C++ 的实现方式使 OO 编程看起来很像过程编程。你需要稍微改变一下你的想法。

在 C++ 中,对象的方法只是作用于对象的过程。但是在真正的 OO 范式中,您应该将方法视为对象可以接收的潜在消息(即字母)。对象接收一条消息(参数表示消息的有效负载,即信件的内容)并根据消息改变其状态。

于 2009-02-10T01:42:27.823 回答
0

有关程序和 OO 之间区别的一个相当直接的示例,请尝试学习 Smalltalk。在 Smalltalk 中,一切,我的意思是一切都是对象。没有 if 语句或 while 循环。您可以通过向其他对象发送消息(也就是调用方法)来实现该功能。一开始它真的让你头晕目眩,但我想你很快就会理解 OO 应该是什么。

于 2009-02-10T05:20:35.350 回答