C ++不适合OOP吗?[关闭]


12

我在这里某个问题的答案之一(不记得是哪个)中读到C ++不适合面向对象的编程。有人提到您可以利用它的功能或类似功能,但不能纯粹从面向对象的角度来理解(我实际上并不真正了解此人的意思)。

这有什么道理吗?如果是这样,为什么?



5
OOP不是一个定义明确的术语,因此讨论C ++是否合适是毫无意义的。
zvrba 2011年

Answers:


31

正如Alan Kay所描述的,“面向对象”一词到底是什么意思?,Alan Kay认为消息传递是OOP的重要部分,但是缺少“带有类的C”(后来变成C ++)。C ++只是具有一些行为的结构,而Smalltalk或Objective-C中的对象是“智能的”,因为它们可以决定如何处理发送的消息。如果类似Smalltalk的对象收到没有实现的消息,则可以延迟添加一条消息,将该消息转发到另一个对象,或执行任意操作。

C ++以面向对象的方式提供的是virtual方法和涉及这些方法调用方式的多态性。当编译器看到class具有虚拟方法的数据类型(或)时,它会为每个虚拟方法构造一个带有槽的vtable。实现虚拟方法的子类会将其实现放在正确的位置,因此客户端代码只需要知道虚拟表中的位置来查找要运行的代码,而不是一直将其解析为特定的功能。这意味着C ++实际上确实具有多种分派的形式,尽管它们都是在编译器中实现的,并且不如Smalltalk式系统那样强大。

如果您将消息传递作为OOP的基础,那么尽管可以使用C ++ 进行传递,但要实现这一目标并非易事。OTOH如果您认为OOP意味着将数据与作用于该数据的函数相关联,则C ++很好。


8
+1-但我一直认为函数调用是传递消息的合理方法。没错,这是一个低级基础,而不是所有内容的高级修复程序-但活动对象模式表明可以从该基础进行构建。
Steve314 2011年

6
因此,这不仅适用于C ++,而且适用于Java,C#,Object Pascal等。最终,Windows API消息传递系统是Alan在OOP中最重要的含义,特别是Delphi处理它的方式
特立尼达

@trinidad是正确的,除了C#实际上支持动态解析。我希望可以公平地说,我们的OOP观念已经随着时间而改变,以解决缺乏消息传递的问题。毫无疑问,供应商表示,面对证据,他们的技术绝对是面向对象的……

@ steve314是的。实际上,这就是ObjC的工作方式,消息发送被转换为一个函数调用,该函数调用查找并调用方法函数。据我了解,消息传递非常重要。

1
@Paul:我不了解Win32 API的有限经验。对象具有可变大小且必须先调用例程以确定对象的大小,分配内存并再次调用的任何API都无法通过我的美观测试。
David Thornley

27

这种讨论让我感到困扰,因为这听起来像是在解释,人们在辩论《圣经》或《美国宪法》的含义,以及原始作者的意思,好像我们认为无关紧要。

你看,艾伦·凯(Alan Kay)是个聪明人,他有一个好主意,与许多其他好主意相抵触,并在Smalltalk和其他语言中实现了。

他不是弥赛亚,OOP也不是一个真正的编程范例。

在许多人当中,这是一个好主意。C ++是否具有来自OOP心态的好主意?当然可以。


8

如果您将OOP定义为封装,继承和多态,则C ++ 支持 OOP。

但是,C ++ 在OOP 方面并不是很出色。原因之一是多态性通常取决于堆分配的对象,尽管使用了智能指针,但堆对象更自然地可以使用垃圾回收语言。

然而,C ++的优势在于通用编程。C ++使您可以通过基于模板的功能编程技术轻松创建高效的通用代码。


4

C ++借鉴了Simula的OOP功能。一个或多个Simula开发人员IIRC认为C ++不是他们的初衷。

C ++有很好的抽象工具,但它是一种混合范例语言,而不是面向对象的语言。那里有面向对象的功能,但是您可以选择的不是“严格的OOP”。

在C ++中,调皮的“选择退出”之一是对方法使用早期绑定而不是后期绑定。这不仅可能-这是默认设置。在Java中,“最终”是相关的,但在某些方面更清晰(它以不仅仅避免微不足道的性能开销的方式指定了意图),而且它不是默认值。

在某些方面,C ++显示出仍在进行早期实验的迹象。即使这样,它仍然是一个很好的工具,它具有许多其他OOP语言所没有的优势。


2
C ++允许非OOP,而C ++允许OOP,对于某些语言来说,它必须允许OOP,因此C ++是一种OO语言。
特立尼达

1
我相信Smalltalk的成名者Alan Kay表示,当他创造“面向对象”一词时,他并不是想到C ++。由于C ++最初是以“带有类的C”的形式出现的,是将Simula类移植到C上的,并且从未进行过彻底的中断,因此,这看起来像是一个早期的实验,也就不足为奇了。
David Thornley

1
@Trinidad:任何语言都允许OOP。我已经在普通的旧C语言中看到了很多不错的OO代码。是的,手工定义所有虚拟方法表很麻烦,但是语言显然允许这样做。
Jan Hudec 2012年

4

强迫所有内容成为类的一部分并不一定会产生出色的OO代码。

要求一个程序差的程序员用Java编程,他们可能会在某个地方带一个类,给它一个静态的main方法,并在其中粘贴1000行代码。我知道我已经看过。

Java有一个switch语句。我已经switch( type ) { case typeA: bundles_of_code; break; case typeB: bundles_of_other_code; break }在C ++和Java代码中看到了等等。

C ++支持许多OO概念,但是它没有定义其标准,但是我想很大程度上取决于您的目标是什么。

C ++中主要的“较差”语义是允许类的复制构造,从而使一个对象变形为另一个对象。您可以禁用此功能,但是不能从函数中返回一个。幸运的是,这在C ++ 0x中已解决。


3

OOP不仅要确保所有内容都属于某个类,或者要确保所有类都在一个类中。完全有可能用“纯粹的OO”语言编写非OO代码。例如,经常指出“ main”是一个全局函数,但是发明一个仅包含静态main方法的类与非OO一样。

C ++最好结合多种因素来工作。这不足为奇,因为这是大多数美好事物运作得最好的方式。OOP通常是那些非常有用的工具之一。


2

C ++可以用于OOP,但它不像Smalltalk那样“纯”。C ++还允许您执行非OOP,这就是人们可能正在谈论的内容。


2

尽管我不同意这种观点,但是C ++的类型系统确实不是纯OOP,这不是“一切都是对象”。数字(尤其是数字)不能像在Smalltalk中那样容易地扩展。例如,您不能重新定义“ 2 + 2”的含义(尽管您可以重新定义“两个+两个”的含义)。

但是大多数人可能意味着许多人使用C ++编写非面向对象的代码,但他们相信,因为他们使用的是“ OOP”语言,所以它们是面向对象的。这不是真的。但是我认为,您可以在Smalltalk中编写可怕的命令性代码,而不比C ++中的体面OOP设计有任何优势。


1

艾伦·凯(Alan Kay)对C ++的完全正确的反对意见是,它是C语言之上的宏语言。

“消息传递”的概念仅仅是将类的实例保存在内存中,并且它们公开了可以调用的方法。在C ++中,使用持有函数指针的vtables“模拟了消息传递”。

要说消息传递在C ++中不存在是不准确的,更准确地说是消息传递是诸如Smalltalk和Java之类的其他语言的组成部分,因为该语言没有预处理外来结构并将其直接移植到C上。

这是一个高度语义化的语言设计论据,我怀疑这超出了发问者的经验水平。

话虽这么说,讨厌C ++的理由有千种,而讨厌C ++的理由却很少。

与其寻找完美的锤子和完美的钉子,不如寻找要建造的完美房屋,然后找到需要经验的正确工具。

同样重要的是要记住,在系统编程中,Alan Kay担心的不是“纯OOP”实际上是C ++的优势。对于每个人自己的...


1
目标C也是从C之上的宏语言开始的,但它是一种面向对象的语言。
Jan Hudec 2012年

1

在我看来,与其说是定义性问题,不如说是可用性问题。

对象是一种抽象,旨在使复杂程序的读取,编写和推理更加容易。对于实际的程序员而言,一种语言是否符合“面向对象”的特定正式定义的所有条件(似乎有几个相互竞争的条件!)并不像它所提供的工具是否适合思考那样重要。就上述对象而言,您的程序-即实际上获得了OOP所谓的生产率收益。

在C ++中,对象是一个非常漏水的抽象,经常迫使程序员解决与这些对象在内存中的结构有关的棘手问题,这些问题比起其他OOP语言更让人联想到直接C语言中的编码。例如,C ++常见问题解答提供了以下批评(以及其他批评):

对于从业人员来说,熟悉除C ++以外的OO系统以及除以特殊方式解释的“封装,继承,多态”三位一体以外的OO定义(使C ++被视为“ OO”)非常有益。例如,声称缺乏边界检查或垃圾收集的环境不是OO环境的说法对于习惯于C ++的人们来说听起来太离谱了。但是从许多角度来看,这很有道理。如果任何人都可以覆盖对象,那么“封装”在哪里?如果处理对象可能导致引用悬挂或内存泄漏,那么系统如何“面向对象” ?分辨给定地点和时间放置哪种物体的能力怎么样?您说该软件可与对象一起使用-它们在哪里?如果找不到,应该如何调试该软件?

C ++是面向对象的,但令人不愉快且不完整:它的用户必须付出很多努力才能确保其数据的行为实际上像“真实”对象,而不是错误的位。就是说,在C ++的整个生命周期中,已经编写了许多代码,其中大多数都是使用类和动态调度的,因此,不言而喻,您可以将其用于实际的OOP。


-1引用FQA应该是一个认真的答案。FQA是一堆扭曲,误解和误解的巢穴。
David Thornley 2012年

@DavidThornley 特定语录是否歪曲,不真实或误解?
Alex P

那里的某个地方。OO语言必须进行边界检查(无论如何有时都内置于C ++标准容器中)和垃圾回收(智能指针是原始垃圾回收)的主张是强制性的和不明确的。关于允许悬挂的引用不面向对象的语言的句子显然是通过公然断言来证明的。我对“能够分辨出什么样的物体”感到困惑;指针类型将其分配给没有虚拟行为的对象,而RTTI则将其分配给具有虚拟行为的对象。
David Thornley 2012年

@DavidThornley FQA的主张是,一种有用的 OO语言应该具有这些东西-与所问的问题相符(C ++是否“合适”?)。我认为关于准系统定义的说法并不能真正解决这个问题……“能力”:通过跟随一些未初始化或先前被覆盖的数据的指针,访问一个不存在的对象的常见错误行为;并且您的程序将很乐意接收该垃圾并将其解释为数据,然后跟随垃圾指针指向其他垃圾数据,直到其到达越界地址或发生一些严重错误。
Alex P

但是,该引言至少有力地表明了这种说法,即没有边界检查或垃圾回收的语言不是OO,并且如果您愿意的话,也可以忽略C ++中包含这些内容的事实。语言是否防止某些类型的错误(无论出于何种原因)的问题与它是否是OO正交。
David Thornley 2012年

-1

格雷厄姆·李(Graham Lee)在这里投票最多是有原因的。重申一下,就其不执行消息传递的意义而言,C ++类似乎并不是真正的对象。我认为这是使人们在学习C ++或oop时会感到非常沮丧的原因。人们被告知面向对象是“ this”,然后被告知C ++会以不同的方式进行操作。好吧,C ++从来没有做过OOP不同的事情。如果您以这种方式思考,您将永远不会理解C ++类的含义,那就是它们只是通过合并抽象和动态行为而对过程范式进行了改进。因此,C ++类在根本上是过程性的,它们只是在过程范式上得到了改进,或者说,它们是C结构的更高级版本。


您的论点有任何实际的支持理由吗?您似乎在断言并声称那些不同意的人一定是错误的,或者如果他们以不同的方式看待它们,或者如果他们共享您对OO的确切定义,那么他们会改变主意。
David Thornley 2012年

很公平。您可以阅读本文。我想我想说的是严格意义上讲C ++不是“面向对象的编程”。但是,如果将OOP定义为具有行为的数据结构,则可以将c ++视为OOP。在我看来,将c ++类视为更高级别的过程编程抽象更为准确。C ++类比Kay样式对象高效得多,但并发性较差。我个人认为c ++类是一个很棒的设计。
annoying_squid

1
感谢您提供的链接,但这仅解释了Alan Kay的意思。此外,我不同意Smalltalk通常被认为是第一种面向对象语言,而Wikipedia同意我的观点,那就是Simula,这是Stroustrup组合成带有类的C的两种语言中的一种。我对您的主张感兴趣,因为C ++类比对象模板更高级的过程编程抽象,但是我仍然不明白您为什么这样认为。
David Thornley

如果我们可以同意的话,对象定向可能是一个主观术语。但是我认为Kay对象是一种更自然的方法,可以使代码解耦并引入并发模块化,从某种意义上说,每个对象都起着类似于微型计算机通过消息传递进行交互的作用。在这种模型下,b / c之间的代码很少甚至没有,整个程序的逻辑可以表示为单元和消息。相比之下,“类”的使用通常需要在两者之间使用一些过程粘合代码(缺少真正的模块化),但是优点是类要高效得多。
annoying_squid 2012年

-1

史蒂夫·耶格(Steve Yegge)说得最好

从最真实的意义上讲,C ++是地球上最愚蠢的语言。它不了解自己。

C ++中的对象系统是如此硬连线,并且在编译时已固定,以至于它与原始的OOP概念相去甚远,后者涉及消息传递,自省,反射,动态分派和后期绑定等。C ++和Smalltalk唯一的共同点是词汇量。


C ++以哪种方式是最不敏感的语言?语言具有感知力是什么意思?如果您说它缺乏反射功能,那是很普遍的,当然也不会让C ++脱颖而出。
David Thornley

2
你到底怎么说他说的“最好”?我不知道那个随机报价是什么意思。
user16764 2012年

+1表示这种事情会在C ++ basher basher中引起很多反响,但必须说-您不能真正地进行OOP而无需反思,因为您没有泛型来处理水平的东西(方面)-生命周期(激活,处置),通用错误处理,通用代理,通用序列化,通用任务并行性-这些最终会污染您的代码并破坏SoC。
vski 2012年

谢谢。我不敢相信-3会说没有反射的语言不是OOP的好例子。
John Cromartie 2012年

1
@JohnCromartie,您能否在回答中详细说明这一点?
Jeremy Heiler 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.