我试图理解过程语言(例如C)和面向对象语言(例如C ++)之间的区别。我从没使用过C ++,但是我一直在和朋友们讨论如何区分两者。

我被告知C ++具有面向对象的概念以及公共和私有模式。变量的定义:事物C没有。在Visual Basic.NET中开发程序时,我从未用过它们:它们有什么好处?

我还被告知,如果变量是公共变量,则可以对其进行访问在任何地方,但尚不清楚与C之类的语言中的全局变量有何不同。也不清楚私有变量与本地变量有何不同。

我听到的另一件事是,出于安全原因,如果需要访问功能,则应首先继承它。用例是管理员应该只拥有所需的权限,而不是所有权限,但是似乎有条件的也可以使用:

if ( login == "admin") {
    // invoke the function
}


为什么这不是很理想吗?

鉴于似乎有一种过程方法可以完成所有面向对象的工作,为什么我应该关心面向对象的编程?

评论

可能重复:C与C ++有何不同?和非OOP语言的局限性;

这种编程范例图可能会为您提供帮助。
+1以抵消某些反对票。如果一个同事问我这样的问题,我可能会有些顾虑,甚至会否决他(假设他旁边有向下箭头)。但是,这个问题似乎是由未来的软件工程师提出的,听起来他在发布之前花了一些时间思考和讨论该主题。我投票赞成帮助他而不是解雇。

@DXM好主意!在同事周围漂浮的向下投票/向上投票箭头...这会产生奇迹。

标准的计数器参数:还有一种汇编方法可以完成您在C中可以执行的所有操作,那么为什么还要关心C? (提示:这全都与提高抽象水平有关。C++设法做到了这一点而又不牺牲C的大部分速度。IMO是C ++成功的主要原因。)

#1 楼

到目前为止,所有答案都集中于您所陈述的问题主题,即“ c和c ++有什么区别”。实际上,这听起来像您知道有什么区别,只是您不明白为什么需要这种区别。因此,然后尝试使用其他答案来解释OO和封装。

我想提出另一个答案,因为基于问题的详细信息,我认为您需要退后几步。 br />
您不了解C ++或OO的目的,因为对您来说,您的应用程序似乎只需要存储数据。这些数据存储在变量中。
“为什么要使变量不可访问?现在我再也无法访问它了!通过公开所有或更好的全局性,我可以从任何地方读取数据没问题。” -是的,根据您当前正在编写的项目的规模,可能没有很多问题(或者有很多问题,但是您只是还没有意识到它们)。

我认为您真正需要回答的基本问题是:“为什么我要隐藏数据?如果这样做,我将无法使用它!”
这就是为什么:

假设您开始一个新项目,打开文本编辑器并开始编写函数。每次您需要存储某些东西(以备以后使用)时,都会创建一个变量。为简化起见,请全局设置变量。
您的第一个应用程序版本运行良好。现在,您开始添加更多功能。您具有更多功能,需要从新代码中读取之前存储的某些数据。其他变量需要修改。您继续编写更多功能。
您可能已经注意到的(或者,如果没有的话,您将来肯定会注意到)是,随着代码的变大,添加下一个功能所需的时间越来越长。随着代码的增加,在不破坏以前有用的功能的情况下添加功能变得越来越难。
为什么?
因为需要记住所有全局变量存储的内容,并且需要记住所有变量的修改位置。而且您需要记住哪个函数可以按确切的顺序调用,如果以不同的顺序调用它们,则可能会出错,因为全局变量尚未完全有效。
您曾经遇到过这种情况吗? ?

您的典型项目(代码行)有多大?
现在将一个项目成像为您的项目的5000至50000倍。另外,其中有多个人在工作。团队中的每个人如何记住(甚至不知道)所有这些变量在做什么?

我上面描述的是完美耦合代码的示例。从时间的曙光开始(假设时间从1970年1月1日开始),人类一直在寻找避免这些问题的方法。避免它们的方法是将代码分成系统,子系统和组件,并限制有多少个函数可以访问任何数据。
如果我有5个整数和一个表示某种状态的字符串,那么仅5个函数设置/获取值对我来说会更容易处理这种状态吗?还是如果100个函数设置/获取了相同的值?
即使没有OO语言(例如C),人们也一直在努力将数据与其他数据隔离开来,并在代码的不同部分之间创建清晰的分隔边界。当项目达到一定大小时,编程的难度就不再是“我可以从函数Y访问变量X”,而是“如何确保只有函数A,B,C且没有其他人接触变量X”。

这就是为什么引入OO概念的原因,也是它们如此强大的原因。它们使您可以对自己隐藏数据,并且您想要有目的地这样做,因为看到该数据的代码越少,则添加下一个功能时,您破坏某些东西的机会就越小。这是封装和OO编程概念的主要目的。它们使您可以将我们的系统/子系统分解为更精细的框,以至于无论整个项目有多大,给定的一组变量只能由50-200行代码访问,仅此而已! OO编程显然还有很多,但是,从本质上讲,这就是为什么C ++为您提供将数据/函数声明为私有,受保护或公共的选项的原因。
OO中的第二个主要概念是抽象层。尽管过程语言也可以具有抽象,但是在C语言中,程序员必须有意识地努力创建这样的层,但是在C ++中,当声明一个类时,会自动创建一个抽象层(是否由抽象决定还是要由您自己决定)将添加或删除值)。您应该阅读/研究有关抽象层的更多信息,如果您有更多问题,我相信这个论坛也将很乐意回答这些问题。

评论


很好的答案,似乎已达到问题的适当水平

–卡洛斯
2011年11月16日14:36

+1 ...主要是针对“从时间的曙光开始(假设时间从1970年1月1日开始)...”开始

–CaffGeek
2011-11-16 15:53

@Chad-我一直认为单行应该给我至少得分:)

– DXM
2011年11月16日在18:20

有一种方法可以解决您在过程范式中讨论的规模问题。这就是所谓的功能。但是解释问题的好方法。

–annoying_squid
16年4月26日在13:57

@DXM-我不确定我是否正确理解答案。我们也可以在过程编程中实现相同的设置/获取功能。我们可以在C语言中编写set / get函数来修改/获取全局变量。同样使用这种方法,我们限制了修改全局变量的函数的数量。即使在OOP中,如果我们也使用set / get方法,我们将在对象外部使用这些方法来更改值。

– kadina
17年8月26日在23:39

#2 楼

嗯...也许最好备份并尝试给出一些有关面向对象编程的基本意图的想法。面向对象编程的大部分意图是允许创建抽象数据类型。对于一个您无疑熟悉的非常简单的示例,请考虑一个字符串。字符串通常会有一个缓冲区来保存字符串的内容,一些可以对字符串进行操作的功能(搜索,访问字符串的一部分,创建子字符串等)。它(至少通常)还有一些要跟踪字符串的(当前)长度和(可能)缓冲区的大小,因此,如果(例如)将字符串的大小从1增加到1000000,它将知道何时需要更多的内存来容纳更大的字符串内容。

那些变量(缓冲区,当前长度和缓冲区大小)是字符串本身的私有变量,但它们并非特定函数的局部变量。每个字符串的内容都有特定的长度,因此我们需要跟踪该字符串的内容/长度。相反,同一函数(例如,提取子字符串)可能在不同的时间对许多不同的字符串进行操作,因此数据不能位于单个函数的本地。

因此,我们最终包含一些字符串专有的数据,因此字符串函数只能(直接)访问它。外部世界可以使用字符串函数来获取字符串的长度,但无需了解任何有关字符串内部的知识即可。同样,它可能会修改字符串-但同样,它是通过字符串函数来进行修改的,只有它们直接修改字符串对象本地的那些变量。

就安全性而言,我要指出的是,虽然这是合理的,但它并不是真正的工作方式。特别是,C ++中的访问专门不旨在满足与操作系统中访问相同的要求。操作系统应该强制执行这些限制,因此(例如)普通用户无法执行为管理员保留的操作。相比之下,C ++中的访问控制仅用于防止事故发生。通过设计,任何想要绕过它们的人都可以轻松绕过它们。它们与将文件标记为只读的顺序相同,因此您不会意外删除它。如果决定删除该文件,将其从只读更改为可读写很简单;将其设置为只读只会使您至少考虑一秒钟,然后决定删除该文件,这样就不会因为在错误的时间按了错误的键而意外删除该文件。

#3 楼

OOP与C的关系并不是您讨论的任何事情。它主要是关于将代码打包到不会/不会(或者有时甚至是有意地)相互影响的区域中。

C使您基本上可以在任何地方运行任何功能。 OOP通过将方法分组为类来防止这种情况,并且仅允许您通过引用包含它们的类来使用这些方法。因此,OOP的一大潜在优势是,您无需经过大量经验告诉您应该进行更好的代码排列就可以了。

评论


-1。 C中没有什么可以使所有功能变为全局的。您可以声明任何静态函数,从而将其范围限制为本地文件。在这方面,C与C ++,Java等没有区别。而且,OOP与语言语法无关,您可以用C编写OO程序,尽管它们比支持OO的语言更粗糙。相反:您不会因为选择支持OO的语言而获得OOP。面向对象是一种编程风格,而不是语言功能。

–user29079
2011年11月18日在7:20

@Lundin:虽然您在技术上是正确的,但是您已经错过了重点。 OOP语言使其默认行为以OOP方式表现。 C没有。

–约翰·费舍尔
2011年11月18日在16:14

OO语言中没有什么强迫您执行此操作。例如,我看到了无数晦涩的C ++程序,而没有任何值得一提的OO。同样,如果您对OO没有任何了解,但是尝试实现类,传统等,则有大约100%的机会创建混乱的程序。

–user29079
2011-11-18 23:36

@Lundin:我认为C ++不是一个很好的例子。它的意思是(或至少是)旨在能够编译C程序而无需(太多)修改。在顶部添加类并不能使其成为C#或Java级别的OOP语言,但确实可以进行这种开发。

–约翰·费舍尔
2011年11月19日,下午1:39

您也可以用Java编写非OO程序,只需在一个巨大的主文件中破解即可... OO仍然不是特定于语言的,如果程序员不了解OO,那么世界上没有语言会保存它们。

–user29079
2011年11月21日在8:00

#4 楼

编写良好的课程应该是一点“信任之岛”:您可以使用它,并假设它做了“正确的事”,并且使您免受常见陷阱的影响。这使一个好的课程成为一个构建块,可以作为一堆函数和变量重用,这些函数和变量虽然可能很好用,但向您展示了它们的所有丑陋之处,并迫使您了解它们如何协同工作,如何初始化它们。好的类应该像USB插头,而过程解决方案就像一堆电线,芯片,锡和焊接头。

没有深入讨论的一点是接口/实现方面。接口描述行为,但不描述实现。因此,列表界面描述了列表的概念及其行为:您将期望诸如add,remove和size方法之类的东西。现在,有很多不同的方法可以实现此列表,例如作为链接列表或使用数组缓冲区。 OO编程的强大之处在于,通过使用接口,您可以在不了解实现的情况下推断出行为。访问内部变量或方法将破坏这种抽象,您不能将一个列表实现替换为另一个列表实现,并且如果不使用类来触摸代码,也无法改进现有的实现。这是需要专用变量和方法的主要原因之一:为了保护实现的内部细节,因此抽象保持不变。

OO进一步走了一步:对于库,您可以为尚不存在的事物定义一个接口,并编写适用于该接口的代码。用户可以编写实现该接口的类,并使用该库提供的服务。这提供了过程编程无法实现的一定程度的灵活性。

评论


接口的概念并不是面向对象语言所独有的。我认为,更大的因素是,在非OOP语言中,模块中使用的几乎所有功能都必须属于同一全局名称空间。这就要求要么使用前缀函数名称来指示其作用,要么使用许多听起来相似的方法来执行完全不同的操作(例如,SetLocation可以用于移动Monster,而SetPosition可以移动PopupWindow,而Move可以是用于调整DisplayCursor的位置)。试图找到正确的“移动”方法...

–超级猫
14年7月18日在16:10

如果编写MyMonstor->时编辑器仅显示适用于Monster类型的方法的列表,则可使操作变得更加容易。如果有许多种不同的事物,每种事物都支持大约十二种操作,则将方法列表中的混乱量减少90%可以极大地降低生产率。

–超级猫
14年7月18日在16:13

@supercat名称冲突是一种语言问题,而不是非OOP问题。另一方面,命名空间是有问题的,因为编译器本质上需要自动重命名该函数或对其进行处理。那么,为什么不手动进行呢?

–annoying_squid
16年4月26日在14:30

@annoying_squid:OOP提供的功能是有效使用函子的主参数类型来选择名称空间的能力。如果我有一个SuperFancyWhizBang类型的变量,则在其上调用SuperFancyWhizBang的方法之一就不需要写出SuperFancyWhizBang类型。表示it.woozle()将指示编译器自动在SuperFancyWhizBang中寻找woozle。

–超级猫
16年4月26日在14:47

#5 楼

有一种方法可以用Turing机器做所有事情,或者至少用汇编语言来完成C或C ++程序最终将要编译成的机器代码。

所以区别不在于什么代码可以做到,但是人们可以做什么。

人们会犯错误。很多。

OOP引入了一种范式和一种语法,可帮助减少可能的人类编码错误的空间大小和概率密度。有时通过将错误定义为某类数据对象非法(例如,这不是为该对象声明的方法)。有时,与标准用法相比,使错误更冗长,或在外观上显得古怪。有时,通过要求接口使用尽可能少的不一致或纠缠的用法(公共与私有)。等。

项目越大,出错的可能性越高。如果仅使用小型程序,可能不会接触到新的编码器。因此,对于OOP为何有价值的潜在困惑。

#6 楼

您的问题似乎更多是关于OOP的目的,而不是区别。您帖子中的概念是封装;并且存在封装以支持CHANGE。当其他类正在访问您的内部时,很难在不破坏它们的情况下对其进行修改。在OOP中,您提供一个接口(公共成员),通过该接口,您可以允许其他类与您的类进行交互,并且您可以隐藏内部结构,以便可以安全地对其进行更改。

评论


只需使用函数原型。那就是封装。

–annoying_squid
16年4月26日在14:32

#7 楼


无论我在哪里读取私有变量都无法访问,而
公共变量又可以访问,为什么不将public公开为global和private
作为局部变量呢?公共和私人的真正用途是什么?请不要说每个人都可以使用它,我想为什么
我们不使用某些条件并进行通话?


我希望您不要一个以上应用程序中的字符串。我也希望您的局部变量在函数调用之间保持不变。这些方面在可访问性方面可能是相同的,但在生存期和其他用途方面却是相同的?他们绝对不一样。

#8 楼

正如许多人所说,一旦编译,任何程序都将转换为二进制代码,并且由于二进制字符串可用于表示整数,因此任何程序最终都只是一个数字。但是,定义所需的数字可能会非常困难,这就是为什么出现高级编程语言的原因。编程语言只是它们最终产生的汇编代码的模型。我想通过这篇关于面向上下文的编程的非常好的论文向您解释过程编程和OO编程之间的区别http://www.jot.fm/issues/issue_2008_03/article4/

从纸上描绘的这张图片可以看出,过程编程仅提供一个维来将计算单元与名称相关联。在这里,过程调用或名称直接映射到过程实现。在图a中,调用m1只能选择调用过程m1的唯一实现。

面向对象的编程为过程编程增加了名称解析的另一个维度。除了方法或过程名称外,在查找方法时,消息分发还考虑了消息接收者。在图b中,我们看到方法m1的两种实现。选择合适的方法不仅取决于消息名称m1,而且取决于实际消息的接收者(在此处为Ry)。

这实际上允许封装和模块化。



图c最终是关于面向主题的编程的,它将面向对象的方法扩展了另一个维度。

希望这对您有所帮助从不同的角度思考OOP。

#9 楼

(+1)问一个您不了解的事物的问题,即使听起来很傻,它也很好。

区别在于面向对象和类的编程。 “普通C”,可处理数据和功能。 “ C ++”添加了“对象和类”的概念,以及几个相关的辅助概念。或在“对象Pascal”之前的“过程Pascal”。

许多开发人员认为学生应该只教一门课程。

例如,没有OO知识的老教师,只教“普通结构C”。 />
或者只教OO而不是“普通C”的“时髦”老师,因为“你不需要”。或两者兼而有之,而不在乎教学顺序。

我想,应该教给学生“结构化纯C”和“面向对象C(C ++)”。首先使用“普通C”,然后使用“ C ++”。

在现实世界中,您需要学习两种范例(以及其他范例,例如“函数式”)。

将结构化程序视为一个巨大的单例“对象”可能会有所帮助。

您还应该强调名称空间(“模块”),在两种语言中,许多老师只是忽略它,但是,重要。

评论


命名空间和重载只会使程序更难以理解。它使识别过程上下文敏感。当您在C ++中看到foo()时,它可以是全局函数,当前名称空间中的函数,与您一起使用的名称空间中的函数,方法,继承的方法,以及是否在函数调用中:它可以是在可以通过基于参数的名称查找来解析的命名空间中,Java和C#的情况类似。在C语言中,它只能是当前源文件中的静态函数,也可以是标头中的一个静态函数。

–卡尔马留斯
2012年8月30日14:53

到处都写MODULE_Foo()可能看起来很混乱,但是至少您完全知道它是哪个功能。

–卡尔马留斯
2012年8月30日14:54

@Calmarius的解决方案显然是不要给任何名称赋foo。

–user251748
17年11月2日在16:22

#10 楼

一言以蔽之,就是项目管理。我的意思是C ++可以帮助我制定有关他人如何使用我的代码的规则。在一个550万行的项目中,我发现面向对象的编程非常有帮助。另一个优点是编译器使我(和其他所有人)遵循某些规则,并在编译时捕获较小的错误。所有理论上的优势也都存在,但是我只想专注于日常实践。毕竟,所有这些都可以编译成机器代码。

#11 楼

面向对象的编程是带有框的过程式编程。

在PP中,您有一个框,一种状态,随着项目的发展,它会变得非常大,每当您忘记一个微小的框时,就会出现副作用。这么大的状态。

在OO中,您有很多盒子,很多状态,并且随着项目的发展,盒子会稍微增长,盒子的数量也会增长很多。

看小盒子仍然很容易,容易看到整个画面,但实际上几乎是不可能的,因为看类和接口隐藏了可能具有重要影响的实现细节。

在函数式编程中,您有许多函数框,并确定每个函数都只有一个入口(参数)和一个出口(返回),而其他外部环境则完全没有其他访问权限。

因为在那里没有状态且没有副作用(通过设计),您可以安全地从整体上分析任何功能,并知道其功能的100%在任何情况下,e。

由于您是用表示动作的逻辑单元对代码进行装箱,因此每个典型动作也只能装一个盒子。

这会缩小与OOP相比,任何大型项目的代码都具有巨大的影响,因为OOP可以在代码库中的不同类中隐藏多个模拟功能。

这也远远超过了PP,因为您可以扩展项目

总之,PP可能是处理简单程序的最简单方法,而FP可能是处理复杂程序的最简单方法。

如果您考虑统一所有代码库和改善代码重用的目标,则应始终使用FP,因为FP是唯一在大规模上有意义的范例,也是唯一的范例具有100%的可重用性(您可以简单地复制粘贴功能,然后在其他地方使用它,而不会产生任何开销)。

您将免费获得100%可靠的单元测试。

您不必编写“ of_doom genius真棒string_1的私有静态最终版”。

您可以免费获得并行性。

#12 楼

简单的一句话区别就是C ++是带有类的C.(尽管现在更多了)我不解释为什么你不想通过阅读Wikipedia上一篇有关C ++的出色文章来了解两者之间的区别。 。这篇文章对您有很大帮助:-C ++(Wikipedia)

在该问题上进行谷歌搜索也将有所帮助。让随机的人解释这可能很棘手。恕我直言,通过阅读比问别人更能理解

评论


我读过这些,但他们只是说了在哪里使用,但仍然没有解决我的问题。

–niko
11年11月16日在6:10

我没有不做任何努力就问了这个问题,但是仍然无法理解区别,所以我遇到了stackoverflow来帮助我

–niko
11-11-16在6:11



@niko,您在这里误解我了。我的意思是,您应该尝试通过阅读来理解两者之间的区别。问你的朋友不好。因为他们会提供自己的理解,可能无法满足您的需求。但是,不用担心,这里有很多同龄人,他们一定会帮助您的:-)

–潘卡吉·阿帕德(Pankaj Upadhyay)
11-11-16在6:18



我没有拒绝投票,但是对“ C ++是带有类的C”感到非常诱惑。我们当中可以实际执行C ++的人努力工作,力图摆脱人们的困扰。

– DeadMG
11年11月16日在10:48

@Pankaj:是的。它是带有类的C语言。绝对不再是带有类的C语言了,将其称为已将近30年了。从那时起,C ++已经走了很长一段路。现在,使用C ++进行编程的人永远不会那样引用它。它会鼓励最坏的习惯和错误的印象。

– DeadMG
11-11-16在12:31