假设我只能在项目环境中使用C ++。防止使用C ++具有但Java没有的某些语言功能是否很好(例如:多重继承,运算符重载)?

我认为原因是:


由于Java比C ++更新,因此如果Java没有提供C ++具有的功能,则意味着该功能不好,因此我们应避免使用它。功能(例如:朋友功能,多重继承)只能由C ++程序员维护或审查,但是如果我们只是像Java一样编写C ++(没有C ++语言特定的功能),则C ++和Java程序员都可以维护或审查代码。
有一天您可能会被要求将代码转换为Java
没有C ++特定功能的代码通常更易于维护
每种C ++语言特定的功能(例如:多重继承)都应该有替代方法来实现在Java中。如果不是,那意味着设计模式或代码体系结构有问题。

是真的吗?

评论

如果您查看您的建议,则是在谈论创建编码标准。您正在创建和遵循标准的事实实际上将提高可维护性。

Java代码是否也应限于使用C ++语言才能找到的功能?因此,例如,不要使用Java volatile,包私有的类成员访问,反射/自省,finally-blocks,检查的异常等等?整个问题有点没有意义... C ++和Java表面上相似,但最终语言却截然不同。

如果人们不愿意使用新功能,语言将如何发展?新功能的目的是通过解决常见问题来使您的生活更轻松。如果用户不使用新功能,那么任何人都没有实现它们的动力。

如果需要Java,请使用Java。如果使用C ++,请使用C ++,而不要使用C ++语法对Java进行一些可怕的扭曲模仿。使用C ++但将自己限制为Java的功能集会使您两全其美。

您会惊讶于差异会以多快的速度咬住您(而且很难)。 SomeObject a = previousObject;在Java和C ++中做非常不同的事情。在Java中,它复制引用,而在C ++中,它复制对象。在Java中,对的修改也会影响先前的对象。在C ++中,您有两个单独的对象。

#1 楼

不。这是严重而错误的指导。


Java功能在某种程度上并不比C ++功能好,尤其是在真空环境中。
如果您的程序员不知道如何使用功能,请培训或雇用更好的开发人员;将开发人员限制在团队中最糟糕的位置,是失去优秀开发人员的快速简便的方法。

YAGNI。立即解决您的实际问题,而不是解决某些将来的问题。


评论


最近有一个问题是,开发人员使用他们通常不编写的语言来审查代码。我认为这里的智慧适用:优秀的开发人员几乎可以在任何一种语言中发现许多基本错误,但是每种语言都有很多问题,以至于使用语言开发人员进行审阅时都可以最大程度地受益。如果您的C ++是“仅Java功能”,则甚至是这样。

– corsiKa
16年1月25日在18:49

+1除了第二点。 OP应该花时间阅读有关“ C ++最佳实践”的知识,以决定应使用哪些功能。关于C ++的最新信息是,将朋友函数和多重继承视为“不良做法”。如果您明智地使用模板和运算符重载之类的内容,则是恕我直言的良好做法。

–some_coder
16 Jan 26'7:54



@some_coder:全都知道何时何地。当我执行基于策略的编程时,我从(可能是多个)策略类继承来用这些策略类需要起作用的成员来扩展宿主类的结构。这就是它的工作方式。另外,operator <<(ostream&,T const&)通常是通过friend实现的。这是关于什么是好的语言功能和什么是不好的语言的笼统声明的问题:它们是很好的建议,除非不是。

–DevSolar
16年1月29日在16:40

#2 楼

仅仅因为语法看起来表面上并不相似,并不意味着这两种语言是兼容的。

1、4和5确实是同一个问题:

现在,我“我不喜欢C ++,但是说“没有C ++特定功能的代码通常更易于维护”只是荒谬的-您是否真的相信Java做到了一切正确,并且在忽略了所有不良特性的情况下采用了所有优良特性?您是否真的相信普遍存在“坏”或“好”功能?如果有,为什么我们没有一种纯粹的语言呢?不,Java当然不是那种语言。这是否意味着Java和C ++没有用?当然不是。

如果领导者决定您要移植到C#而不是Java怎么办? C#不仅支持重载运算符,而且还是默认设置-如果您需要人们使用例如人们总是会犯错误,而不是obj.Equals(obj2)。即使仅遵循两种语言的共同特征,也有不同的期望和不同的文化。如果您在C ++中执行类似obj == obj2的操作,人们会立即发现您是新手。如果在C#中使用if (myField == null),人们会发现您还不是真正的C#本机-C开发人员学会使用“翻转”变体的原因在C#中不再存在。

使用您的逻辑,我们应该坚持使用机器代码或汇编语言或COBOL,因为为什么要更改为Pascal之类的东西,而只是添加程序员必须学习的新功能?当它甚至没有循环时,为什么还要使用像SQL这样的东西呢?当SQL没有循环而X却有循环时,为什么我们还会使用SQL以外的东西呢?

Java程序员当然不能维护C ++代码。我不明白您是怎么想到这个主意的-将C ++限制为仅能与Java完全相同的功能时,还剩下什么?您甚至都不会获得方法调用-甚至不会得到函数调用。同样,仅因为这两种语言都使用花括号,并不意味着这些语言在任何方面都可以互换。

无论您做什么,转换类似Java的C ++代码都将极易出错。差异太多了。如果您需要用另一种语言重写应用程序,请考虑将所有组件模块化的合理方法,以便可以在不破坏整体的情况下更换部件。但是最后,YAGNI –不管您做什么,都要使代码“准备好转换为Java”要付出巨大的代价。到时候最好把时间花在添加或改进您的功能上。

我们使用不同的语言,因为它们为我们提供了解决问题的不同工具集。如果您需要在任何地方都能运行的可执行文件,请使用Java。如果您希望代码“无处不在”进行编译,则C ++可以正常工作。如果您想要易于理解和解析的代码,请使用LISP或其他工具。但是我可以告诉您一件事-用一种语言编写代码就像您用另一种语言编写一样总是错误,并且您会遭受痛苦。更不用说当您实际雇用C ++的人时,他将运行第二个,他会看到“与Java兼容”的代码。而且... Java家伙也会做同样的事情。您知道,即使“知道” C ++和Java,我也会像地狱般奔跑:)

实际上,我不得不处理一个Pascal开发人员编写的(普通的)C代码,该开发人员似乎认为与您一样。他使用if (null == myField) s重新定义C的外观,使其更像Pascal,并带有“ BEGIN转换为{”之类的内容。结果是相当可预测的-C或Pascal开发人员都无法理解的代码,以及由于在C​​之上泄漏Pascal的“抽象”而导致的大量错误。从今天的角度来看,Pascal和C几乎是相同的。即使使用C <-> C ++也有很大的不同,这仍然像C ++ <-> Java之类。

评论


“如果您想要易于理解和解析的代码,请使用LISP或其他工具。”我不同意这一点。 Lisp解析起来很简单,但是正因为如此-因为它是在解析器的知识和有效构建它们的原理还处于起步阶段的时候创建的,所以他们猛烈地抨击并采用了最荒谬的简单化方法那可能行得通-您不会从现代语言中获得很多语法上的好处。因此,它很容易解析,但一点也不容易理解。人们称其为“丢失多余的括号”是有原因的。

–梅森·惠勒
16 Jan 25 '21:58



@MasonWheeler这是一个问题,C程序员将其称为LISPers:P。计算括号-与典型的C ++程序中的括号差不多。真正的区别是它们的位置(myFunc()与(myFunc)),这有很好的理由。基于LISP的语言仍然非常流行,尤其是在数学/物理学界。最主要的是,LISPy语言对现代C风格的程序员非常陌生-但这并不是忽略它的理由。 Scheme,Clojure和某种程度上基于ML的语言(OCaml,F#...)确实非常轻便。

–罗安
16年1月26日在8:01

@Luaan我可以肯定地说LISP在物理上并不流行。该领域的两种主要语言是FORTRAN和C ++。 FORTRAN之所以“受欢迎”,是因为其中写了很多旧代码,但是几乎所有新程序都是用C ++编写的。作为研究物理学家,我从未见过甚至从未听说过LISP程序。并不是说它们不存在,但是这些语言绝对不受欢迎。

–詹姆斯·马塔(James Matta)
16年1月26日在19:13

@Luaan我们可能会或可能不需要更多的软件开发人员。我们绝对不需要更多的CS毕业生。这就像在说:“我们需要更多的结构工程师,所以我们需要更多的理论物理学毕业生。”

–Miles Rout
16年1月26日在20:36

@ user1717828避免像if(myField == null)好像(myField = null)那样产生误输入的令人愉悦的效果,这将编译出很好的C / C ++,但可能不会达到您的预期。另一方面,如果(null = myField)会引发错误,因为您无法分配给常量。

– Wlerin
16 Jan 27'5:58



#3 楼

我将按顺序回答您的问题。


如果Java没有提供C ++所具有的功能,则表示该功能不好,因此我们应避免使用它。 />
是的,Java中不存在的任何功能都是硬盘驱动器上的垃圾。必须从您的代码库中刻录。那些不听话的人会被狼吞虎咽,他们的灵魂被用来安抚RAID神。


具有C ++特定功能(例如:朋友功能,多重继承)的C ++代码只能维护或经过C ++程序员审查,但是如果我们只是像Java一样编写C ++(没有C ++语言特定的功能),则C ++和Java程序员都可以维护或审查代码。

如有疑问,请为团队中最不称职的成员。读取代码的频率远高于编写代码的频率,而您可以编写的聪明代码太难读了。您的前台工作人员无法理解的代码审查应被拒绝。要提供帮助,请在周末教他们如何在Visual Basic 2.0中进行编程,然后以您使用的任何语言来模拟他们的编码样式。


您可能会被要求将代码转换为Java。有一天

正确!但是为什么停在Java上呢?您可能需要一天将代码转换为基本代码,汇编程序和/或perl。由于存在各种语言的perl解释器,因此只需将程序编写为长的perl字符串,然后以选择的语言将参数编组到其中即可。

现在,当您需要更改语言时,只需重写


没有C ++特定功能的代码通常更易于维护。

确实,使用较少功能的代码更易于维护。并且由于所有语言都等效于Turing Machine,并且Turing Machine具有所有编程语言中最少的功能,因此让上述perl解释器实际运行可解决您问题的Turing Machine(磁带和所有磁带)。


每个C ++语言特定的功能(例如:多重继承)都应具有在Java中实现的替代方法。如果不是这样,则说明设计模式或代码体系结构存在问题。

C ++语言特定的功能实际上具有重要的用途。因为它们不是Java,所以它们是恶心的,并且使用Java的人可能被称为异端。如果C ++没有这些语言功能,那么您将找不到需要牺牲的语言。 C ++语言功能解决了问题!


C ++和Java具有一组不同的功能。在C ++和Java的交集中进行编程所产生的代码放弃了这两种语言的大多数优点。

Java的部分开发是对某些C ++功能滥用的一种反应。这并不意味着反应是合理的,尤其是几年以后,当功能成熟时。

操作符重载可以做可怕的事情;但是没有一种语言可以阻止用这种语言编写可怕的代码,除非它阻止了所有用该语言编写的代码。

使用操作符重载也可以做得很优雅。诸如复数或矩阵类之类的简单事物的工作方式类似于复数或矩阵。

应谨慎使用Java中不可用的C ++功能。仅仅因为您当前的开发人员在其当前技能水平上不了解某个功能,并不意味着该功能永远不应该被使用。同时,仅仅是因为您可以使用功能,并不意味着您应该这样做。但是,在Java繁重的商店中,抵抗非Java风格的功能的抵抗力要强得多。

最好通过重写来完成语言之间的代码转换,无论如何它们在结构上相似。如果没有这样的重写,任何尝试都将失败。

许多C ++特定功能都是维护的奇迹。类型擦除(如std::function)使您可以取消层次结构的耦合,从而减少依赖性。智能指针和确定性生存期以及RAII减少了运行时意外情况,并避免了资源模板化。大量的静态类型检查意味着代码无法编译,而不是无法运行。混入可减少代码重复。 ADL允许类型层次结构之间接口的临时独立扩展。 Lambda允许您在使用代码的旁边编写代码。转发和移动可减少副本,并使功能样式(无副作用)编程高效。运算符重载降低了线路噪音,并使代码看起来更像其正在建模的数学。

当心Turing Tar坑。您可以用任何语言(包括带有磁带的原始图灵机)实施所有操作,但这并不意味着您应该这样做。在C ++中使用Java风格的结构模拟C ++功能是一个可怕的想法。它将导致无法维护的代码,任何人都无法阅读或理解。

您可以从Java设计中汲取灵感并将其移植到C ++。我非常喜欢Python语言功能并用C ++实现它们,因为我喜欢语法。但这并不意味着我将类方法写为带有显式自我的静态方法,然后编写将非静态方法调用转发给它的包装器。

现代C ++并不完全像Java模仿并拒绝的语言。不要被一种语言的功能所束缚;没有“一种真正的语言”。了解新语言及其功能,并吸收其独特性。

评论


-1,long不清。

– djechlin
16年1月25日在23:05

-1论证,稻草人论证

–user949300
16年1月26日,下午3:08

+1,正确解构所问的问题,我笑了:)

–猫
16年1月26日在15:15

+1。有趣,但要点。非常适合实际阅读的人。

–路易斯·马苏埃利(Luis Masuelli)
16年1月28日,下午3:32

“在C ++和Java的交集中进行编程所产生的代码放弃了这两种语言的大多数优点。”打钉子在头上! +1

– Ajedi32
16年1月28日在20:39

#4 楼

我只是想回答你的原因:


我不明白你是怎么得出这个结论的。不同的语言具有不同的功能。取决于范围,语言结构,有时创建者的喜好以及许多其他原因。语言的某些功能可能不好,但是您的概括是错误的恕我直言。
像Java一样编写C ++可能会导致代码变差。例如。如今,对于C ++ 11,我避免使用new / delete,而是使用共享指针。在您的情况下,我将仅依赖于new / delete。如果您的程序员只懂Java,请对其进行培训或雇用更好的Java。
这可能会发生吗?您为什么不首先用Java编写?我认为用新语言从头开始重写程序通常不是一个好主意,您需要为这种风险提供一个很好的理由。
这只是一个假设。
高度依赖IMHO取决于您的方案或使用情况案例。


评论


Java程序员也不会使用delete。

–PaŭloEbermann
16年1月25日在21:27

我不得不修复由于Java程序员不了解删除而导致的内存泄漏。我记得,在至少其中一种情况下,也不需要动态分配(新的)。

–索伦
16年1月25日在23:53

@EthanKaminski是的,这就是您可以轻松发现C ++新手的方法,尤其是那些来自Java背景或类似背景的人。别再用新东西了,该死!

–罗安
16年1月26日在8:02

@PaŭloEbermann是的,甚至更糟。

–西蒙
16年1月26日在9:12

“在您的情况下,我将仅依赖于new / delete”-有趣的是,我会以为“仅具有Java(类似)功能”的C ++习惯用法将专门使用make_shared。

–凯尔·斯特兰德(Kyle Strand)
16年1月27日在16:18

#5 楼

Java具有C ++所不具备的功能,例如内置,快速,可靠的垃圾收集器,单根对象层次结构和强大的自省功能。

Java的其他功能旨在与C ++一起使用。 Java独有的功能以及Java对C ++功能的许多遗漏都是可能的,因为新功能弥补了这些不足。例如,Java没有具有确定性析构函数的堆栈分配对象,但最终有了块(自Java 7开始使用try-with-resources)和垃圾收集器来弥补这种不足。

C ++最终没有块或垃圾回收。如果您不使用析构函数(因为析构函数在Java中不存在)(我不算终结器),那么您将处于C级的资源管理(即所有手册),除了您甚至无法对清理进行分组进入您要转到的清理块,因为Java也没有goto。您是否真的认为可以提高可维护性?

Java具有一个总体的对象层次结构,其中每个类最终都派生自Object,并且少数基本类型也可以自动装箱到此类中。这样就可以一次编写对象容器,以保存指向对象的指针。 Java 5引入了泛型,该泛型摆脱了此类容器的强制转换,但仍可以编译成几乎相同的代码。

C ++没有这样的层次结构。为了方便编写适用于多种类型的容器,可以使用模板,这些模板是编译器根据不同类型的需要实例化的蓝图。您会禁止使用模板(和宏),还是走C语言路线,要么一遍又一遍地为不同类型编写相同的容器代码,要么使用空指针? (等等,Java没有空指针!)确定要增加可维护性吗?

体面的语言具有旨在一起工作的多种功能。通过禁止语言A的功能(因为语言B没有这些功能),您正在削弱语言A,因为您无法同时从语言B中添加使B成为一个连贯整体的功能。

那不是说您一定不要限制C ++允许的功能。 C ++是一门古老的,历史悠久的语言,它强调使程序员能够在安全性和易用性上完成自己想做的事情,并且并非所有其灵活的功能对于构建良好的程序都是必需的。有许多编码标准限制了某些功能的使用。例如,Google的指南大多禁止多重继承,复杂的模板和例外(尽管最后一个是出于历史原因)。但是没有功能被禁止是“因为Java没有它”。仅在C ++框架内考虑了这些功能。

评论


经验丰富的C ++老手通常会拒绝Google编码指南。恰恰是因为现代C ++使用了这些功能,所以它要好得多。是的,这使它与众不同。

– Jan Hudec
16 Jan 25 '13:36

请注意,C ++没有finally块,但是它具有RAII,这在大多数情况下要好得多。而且,又一次不同。

– Jan Hudec
16 Jan 25 '13:36

对于大多数用途,Java的Object几乎都是一个void *-还是,哎呀。

–昆汀
16年1月25日在13:44

除了功能选择之外,还有样式和成语的问题。如果程序使用其编写语言的常规习惯用法,则通常更易于阅读和维护。即使仅使用类似Java的功能就可以编写C ++程序的一部分,结果也将是奇怪的,令人陶醉的C ++。

–Patricia Shanahan
16年1月25日在14:48

我会在正确的轨道上(“不要这样做”)对这个答案表示赞同,但是我不能忍受Java一定程度上比C ++更高级的基本前提。 C ++不需要垃圾收集器或单根对象层次结构,就像Java不需要... err ...抱歉,我不知道如何完成这句话,因为我错过了Java中的确定性析构函数,并且最终不是他们的替代品。两种语言根本不同。

–DevSolar
16 Jan 27 '15:20



#6 楼

当您已经得出一个似乎完全合理的结论的数字时,我一直在争论是否要麻烦发布另一个答案:您的想法基本上是一场灾难,等待着发生。但是,我认为他们未能指出该结论背后的一些高度相关的原因。
Java和C ++之间的差异远比您似乎关注的细节深得多。 />
例如,您谈论禁止在C ++中进行多重继承。首先,我要指出的是,这根本没有讲到重点。 Java将“接口”定义为与“类”分开的事物。一个类仅从另一个类继承,但是可以实现任意数量的接口。

C ++不会这样区分两个概念。 C ++提供的最接近的模拟Java继承自另一个类。因此,为了使两者之间保持合理的一致性,您可能需要在C ++中使用多重继承,但是您希望以与Java相比将类与类限制接口的方式大致相同的方式来限制某些基类。它指定了函数签名,但至少在大多数情况下没有实现)。

但这只是勉强了解两者之间真正差异的表面。实际上,在Java代码很可能定义接口以及实现这些接口的类的地方,C ++代码很可能会定义一些模板,这些模板将与满足其要求的任何类一起工作(而不仅仅是为实现接口而专门定义的那些模板) (s)指定)。

如果老实说,您想要的代码基本上是“使用C ++语法的Java”,那么几乎可以肯定,您必须禁止任何与后者类似的东西。您需要将模板的使用限制在Java泛型支持的大致“ T容器”级别。不幸的是,这样做会导致C ++代码混乱,以至于没有人可以维护它,而更不用说将其转换为其他编程语言的长期可能性了。

确实希望将来可以将代码转换为其他语言的代码,力求使其尽可能简洁和易读。理想的情况是编写伪代码并让其执行。编写良好的现代C ++方法比您建议的子集更接近理想。无论如何编写,如果要翻译成Java,就必须实际翻译代码,而不仅仅是个别语句的语法。

评论


许多C ++功能可以通过某些方式很好地映射到Java概念,而不能以其他方式使用。程序的某些部分将需要语言功能的重叠子集之外的内容,并且尝试编写诸如“使用C ++语法的Java”之类的部分将产生可怕的混乱。另一方面,代码的许多其他部分可能需要共享子集之外的任何内容,而对于那些没有令人信服的理由需要超出共享子集的代码部分,尝试保持在共享内是有帮助的。

–超级猫
16年1月28日在18:19

大概在您说“可能需要”的地方,您的意思是:“可能不需要”?假设这样,那么我倾向于同意。

–杰里·科芬(Jerry Coffin)
16年1月28日在18:23

对。如果有必要支持一个支持Java但不支持C ++的平台,则几乎可以肯定必须重新编写部分代码,而这些部分是否已使用Java友好的技术编写也无关紧要。仍然会被重写。但是,可以编写其他部分,而无需完全重写即可迁移它们,并且在某些情况下,这样做所需的额外成本可能很小。

–超级猫
16年1月28日在18:38

@supercat:OTOH,考虑到支持Java但不支持C ++的平台数量,这几乎使我成为解决问题的一种解决方案。

–杰里·科芬(Jerry Coffin)
16年1月28日在18:47

一段时间以来,浏览器对Java小程序的支持比对C ++小程序的支持要好。但是,浏览器对JavsScript的支持(与Java没有关系)已经得到了足够的改进,以至于基本上都被这两者所取代。

–超级猫
16年1月28日在19:11

#7 楼

如果要使用X语言编写代码,请花一些时间正确学习该语言并使用其提供的所有功能来帮助您解决问题。当您尝试将一种语言从一种语言转换为另一种语言时,不管是日语到英语还是Java到C ++,都会发生坏事。最好先对问题有一个很好的理解,并以最适合所使用语言的方式来表达解决方案。

几年前,我看到一个C语言程序没有缩进和每条语句都从第7列开始,因为代码的编写者是一位正巧使用C的Fortran程序员。其他Fortran程序员对于这些称为指针的新奇事物感到不安。我不愿意提起指向指针的指针,我认为它们会当场晕倒。

想象一下,将来雇用某个人来维护此代码。如果这是好的C ++代码,您将可以聘请有能力的C ++开发人员,他们应该能够找到解决方法。如果它是“ C ++中的Java”,那么C ++和Java开发人员都不会很容易理解代码。

#8 楼

您所有的原因都可以被驳斥:


如果Java没有提供C ++所具有的功能,则表明该功能不好,因此我们应避免使用它。 />

并不表示该功能不好(没有任何功能本来就不好)。这仅意味着该功能经常被滥用(或者由于基本概念(如直接指针与垃圾回收)而无法实现)。顾名思义,Java的目标是更简单,对程序员更友好,因此删除了证明自己易于滥用的功能。


具有C ++特定功能的C ++代码(例如:朋友函数) ,多重继承)只能由C ++程序员维护或审查,但是如果我们只是像Java一样编写C ++(没有C ++语言特定的功能),则C ++和Java程序员都可以维护或审查代码。


哦可以吗?让我们看一下最简单的C ++代码:

int len = mystring->size();


糟糕,没有使用“特定于语言的”功能,但是Java开发人员已经无法维护它!因为在Java中,您用“。”取消引用。而这里是“->。


有一天可能会要求您将代码转换为Java


或者C#。或者Haskell。或者Python,Ruby或COBOL(是的,您可以!)。如何告诉未来?


没有C ++特定功能的代码通常更易于维护。


恰恰相反,引入了每个功能都是为了使编程更容易因此更易于维护,例如:在浮点数上运行一个程序,现在将其升级以处理复杂的数字。

每个C ++语言特定的功能(例如:多重继承)都应该具有在Java中实现的替代方法,否则,这意味着设计模式或代码体系结构存在问题。 br />
但是Java具有多重继承!它称为“接口”。 Java实现是一个有问题的解决方法,它可以避免由于使所有事物都源自Object而导致的可怕的菱形。这是通过引入interface来完成的,其唯一目的是成为并非源自Object的东西。 C ++从来没有这个问题-没有强制性的通用基础,因此每个类都可以充当没有可怕钻石的接口。

侧面说明:Java最近引入了...接口中的具体方法。 C ++新增了一项功能,它总是必须解决一个从未出现过的问题。

您还只提到了很少的“ C ++拥有但Java没有的东西”。 C ++和Java之间最大的区别之一是对内存布局的控制。您可以创建指向对象的指针数组(就像在Java中一样),也可以创建连续的内存块。现在,如果我担心C ++功能可能会误导Java开发人员,那么在我的列表中,像这样的隐藏和微妙的功能将比明显可见且一眼就能识别的东西(如多重继承或重载运算符)高得多。 >
底线:干净代码就是干净代码。 Java或C ++-相同。保持简单。不必要的复杂性是错误代码的主要原因。

评论


Java提供了某些功能和保证,而这些功能和保证在提供C ++所有功能的语言中是无法支持的。例如,一种语言在提供C ++中包含的通用形式的多重继承时,就不允许动态类型加载和Java的所有身份保留类型转换。

–超级猫
16 Jan 25 '20:00



@supercat我不明白你为什么在这里这么说。问题不是关于不能在C ++中复制的Java功能,而是关于Java放弃的C ++功能。

–Agent_L
16年1月26日在8:19

我的观点是,Java的某些功能未包含在C ++中,而是Java的某些功能与C ++所包含的其他功能从根本上不兼容,因此,任何语言都不能同时支持两种语言(例如C ++ / CLI等语言)具有支持C ++功能的类型和支持Java类功能的类型,但是它们有效地存在于互斥性有限的单独Universe中)。

–超级猫
16年1月26日在16:45

#9 楼

不,您通常不应该像Java那样编写C ++,并且绝对不应该忽略Java中不存在的C ++语言功能。

一方面,Java被垃圾收集,因此具有没有等效的C ++“ delete”关键字。好的,因此您无需删除即可实现程序,因为按照您的规则,这是不允许的。

恭喜,您现在发生了内存泄漏;)。同样,这也不是理论上的-我已经在开放源代码游戏中看到了这种确切情况。

类似地,Java没有像C ++指针那样的东西,它排除了许多常见的函数调用约定。

C ++的某些功能应避免使用(请参见下文),但是“不使用Java”不是一个很好的试金石。


更好的准则如下:


编写适合您的语言,环境和工具的代码。
编写团队可以理解的代码。
确保您的团队在给定领域有能力。

项(3)意味着,如果不接受C ++培训,则不应拥有C ++中的Java程序员代码。有一些细微但非常重要的差异,如果他们试图将其视为Java的怪异方言,他们可能不会学到。

项目(2)表示,如果您的团队特别不满意多重继承(例如),并且如果有一个适当的解决方案不使用它,那么最好使用该替代解决方案。但是,这具体取决于您的团队。另一方面,如果您的团队对该替代解决方案比对多重继承更不满意,请使用多重继承!


最后,C ++的语言功能可以说应该避免。如果您想知道这些是什么,请询问C ++程序员,而不是其他语言的程序员。首先是指针算术(没有通用共识)和goto。

#10 楼

其他答案中已经有一些优点,但是我想提供一个更完整的答案,分别解决您的问题和陈述。


如果Java没有提供可以C ++具有此功能,这意味着该功能不好,因此我们应避免使用它。

这已经得到了很好的回答:Java并不是C ++的“好部分”,也不存在这样做的理由。
特别地,尽管每个C ++功能的优点值得商,,但C ++ 11 / C ++ 14的许多不属于Java的功能并不一定要排除在外,因为Java设计师认为这是一个糟糕的主意。作为示例,直到版本8为止,Java都没有lambda,但是它们是在C ++ 11标准中引入到C ++的。在Java 8之前,您认为Java中缺少的C ++功能由于设计“不佳”而在设计中缺失了,这意味着作为语言功能的lambda并不“好”(到处都是LISPer的恐怖,尽管它们可能会惊恐地听到您显然确实喜欢Java)。但是现在Java设计师已经将他们的批准印章(TM)放到了lambda上,所以它们现在是一件好事。
要深入研究,即使在Java 8中,lambdas-as-closures也没有那么灵活作为C ++ 14的lambda,但这可能是由于JVM体系结构的局限性,而不是有意识的决定,从语言设计的角度来看,更灵活的方法是不好的。


C ++特定功能(例如:朋友功能,多重继承)只能由C ++程序员维护或审查,但是如果我们只是像Java一样编写C ++(没有C ++语言特定的特征),则C ++和Java都可以维护或审查代码程序员。

这是我要回应的主要内容。
从广义上讲,从不十分熟悉您所使用的语言的程序员那里获得代码审查可能会有一些价值。他们可以为您提供有关函数/方法名称和注释的清晰度的宝贵反馈,并且(如您的问题所正确暗示的那样)(如果该语言类似于他们已经知道的一种或多种语言),他们可以遵循基本程序流程
但是,并非如此的情况下,这种审查永远不会与真正了解您所使用的语言的开发人员一样“好”或“等效”。从本质上讲,这是因为使一种语言看起来像另一种语言通常会隐藏细微的差异,而使一种语言表现得像另一种语言(特别是在C ++和Java的情况下)对于该语言而言可能不是惯用的,并且/或者可能仍然过于混乱对于审稿人。
首先,让我们考虑一下使C ++“看起来像” Java意味着什么。作为一个简单的例子,您可以使用new来实例化对象,就像在Java中一样:
Foo foo = new Foo();

但是以这种方式实例化的对象使用->而不是.来调用方法,因此如果您希望方法调用看起来像Java,您必须改写:
Foo& foo = *new Foo();

,但这是不习惯的;特别是,稍后必须使用delete &foo清理内存,一些经验丰富的C ++开发人员可能甚至没有意识到这是合法代码。无论哪种方式,到处都是有趣的非Java符号,因此我们无法完全使Java语言“看起来像”。 (您可以使用*new或更糟糕的是#define New *new消除#define new *new,但是您只是乞求其他开发人员讨厌您。)如上所述,delete在Java中不存在,因此无论如何(如在另一个答案中提到),您真的无法像在Java中那样使对象使用“看起来”没有内存泄漏。
但是现代C ++包含智能共享指针,其行为与Java的内存管理变量引用非常相似。因此,在Java的任何地方都可以编写Foo foo = new Foo();,而可以编写:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();

现在,您正在使用的语言功能实际上很像Java的内幕。但是突然之间,您有很多要向非C ++审阅者解释:shared_ptr是什么? make_shared的微妙棘手的“陷阱”是什么? (它使用完善转发,这会导致某些失败情况,并且可能导致调用“错误的”构造函数。)为什么需要使用->调用方法,但是编译器允许将.与某些方法一起使用? (shared_ptr拥有自己的方法。)如果存在方法Foo::reset(void),那么粗心的开发人员可能会尝试使用foo.reset()进行调用,如果调用时只有一个共享指针指向Foo的该实例,它将删除基础内存。并消除foo,并且Java开发人员不太可能解决此问题。此外,C ++有很多特定于该语言的陷阱。尽我所知,大多数C ++开发人员通过逐步开发自己的“安全” C ++习惯用法来学习如何应对这些陷阱,这对于他们或他们的开发团队而言往往是独一无二的(例如,参见提及Google编码惯例及其评论说:“经验丰富的C ++老兵通常会拒绝Google编码准则”)。所有声称这种语言可能太复杂的说法(至少以我的经验)似乎通常都带有“嗯,别用错了”的一些变体。我意识到这是对C ++社区的高度消极看法,当然有经验丰富的开发人员更愿意为语言学习者提供帮助,但似乎在某些方面存在防御性。未定义的行为(例如,请参见上面我的“陷阱”链接中的大部分讨论)。
Java开发人员根本不会通过代码审查来发现和纠正这些陷阱。


有一天您可能会被要求将代码转换为Java。

尝试在设计阶段考虑将来您的代码可能发生的事情,这是完全有效的,甚至是值得称赞的。
但是,首先,这种特殊的考虑似乎很遥远可能性:代码通常可以按原样重复使用(例如,您可以使用JNI接口将某些或所有有效的C ++代码插入到将来的某些Java软件中),也可以完全重写而不是直接手动“转录”。
其次,您稍后会说,

每种C ++语言特定的功能(例如:多重继承)都应具有在Java中实现的替代方法。...

这实际上取消了摆脱“转换为Java”的观点。如果软件是用惯用的C ++编写的,然后转换为惯用的Java,则没有理由期望通过将C ++功能与Java功能进行精确的一对一映射来完成这种转换。 >

没有C ++特定功能的代码通常更易于维护。

不清楚您的意思是什么,但实际上我对此有些同意:除非您非常小心,即使您小心一点,C ++功能也可能导致可维护性问题。 C ++ FQA Lite(批评该语言及其忠实拥护者的网站,至少看起来似乎对它的理解相当好)指出:

... 80%的开发人员最多理解20%语言。对于不同的人,这是不相同的20%,所以不要指望他们理解彼此的代码。

请注意:如果您是C ++的狂热者,而您到了我的答案,并倾向于跳到评论中争论说FQA的作者实际上并不了解C ++或在大多数论点中都是虚假的,请注意,(1)在我引用他之后恰好两句话,我承认FQA是一个非常有偏见的来源,并且(2)对于我想说FQA作者是否理解C ++来说,这并不重要,而我并没有试图抨击C ++,并且您应该阅读本文章的其余部分,而不要仅仅因为我引用了FQA就认为我是反C ++的人。注释的结尾。
类似地,Linus Torvalds基本上出于这个原因讨厌C ++(警告:链接涉及到很多咒骂,都是真正的臭名昭著的Linus风格)。
显然,这些都是非常有偏见的事情,但是甚至C ++的拥护者也经常说您不应该使用整个语言功能集(再次,请参阅Google编码指南;而且,C ++的创建者Bjarne Stroustrup公开声明:“在C ++中,有一个因此,我认为C ++功能可能太容易被滥用,特别是如果您来自Java背景的话,我认为这是有好处的。此外,通过将自己限制为某种语言子集来减轻这些问题的想法是有好处的。
但是,基于另一种语言来决定使用哪个子集似乎不是正确的方法,除非“不同的语言” ”是C,因为确实存在C ++语言的C类子集。 (Linus在上面的话中提到了这一点,Scott Meyers甚至将此子集称为“子语言”。)Java的运行时范式(垃圾收集,在VM上运行)与C ++根本不同,因此尚不清楚有任何有用的经验教训可以从中汲取有关C ++的用法,并且如上所述,尝试直接从Java汲取有关C ++的经验教训可能会导致非常惯用的代码。
相反,在了解如何习惯使用该语言的情况下,尝试定义该语言的“可接受子集”。如果您想要一个限制性很强的子集,而该子集仍然可以利用C所提供的C ++以外的许多功能,那么上述Google Coding指南可能是一个不错的起点。当然,您会得到开发人员说,对于Google的某些限制没有“合理的论据”,但是除非您打算聘请Alexandrescu远离他在D语言上的工作(它本身应该告诉您一些东西),否则大概还可以。当然,这比尝试将C ++转换为Java更好。
另一个代码准则集的另一个良好起点是新的C ++核心准则,这是Bjarne Stroustrup和Herb Sutter正在进行的工作。
解决C ++缺点的唯一其他方法是选择其他语言。听起来您喜欢Java,并且您认为该项目最终有可能会转换为Java。如另一个答案所述,您可以...从Java开始。
您可能真的需要使用Java以外的其他东西有两个原因:

您确实需要运行表演。在这种情况下,将C ++当作Java对待实际上可能无济于事,因为类似Java的技术(如共享指针)会降低您的运行时性能。
您需要该软件在无法运行的晦涩平台上运行还不支持JVM。在这种情况下,您可能会陷入具有GCC或Clang前端的语言。 C和C ++是很明显的候选者,但是您也可以研究Rust之类的东西。 (快速插件:我还没有广泛使用Rust,但是它看起来很棒,我渴望尽快从事一个主要的Rust项目,而且我认为考虑开始C ++项目的每个人都应该考虑使用Rust作为替代方案。)



每个C ++语言特定的功能(例如:多重继承)都应具有在Java中实现的替代方法。如果不是这样,则意味着设计模式或代码体系结构有问题。

我已经解决了一些问题,但是我故意省略了第二句话。
我没有确信constexpr之类的东西在Java之类的部分JIT语言中没有任何意义,这表明体系结构无效。我对这样的想法持开放态度,即过度使用模板元编程可能比其应有的麻烦更大,尤其是现在存在constexpr来进行编译时函数评估,但是从constexpr的情况中可以很明显地看出,它没有设计缺陷如果您正在使用它:您只是在确保甚至在运行代码之前就进行了一些计算,这极大地提高了性能(例如,参见Benchmark Game的n体问题的此项,其性能优于其他各项另一种用C ++编写的语言,速度是最快的Java实现的两倍。

评论


FQA作者肯定属于“最多了解20%的语言”组。那里有一些实际上是错误的答案,还有更多的答案是错的。

– Ben Voigt
16年1月27日在20:44

C ++ FQA中的许多(几乎全部?)都是无稽之谈。现代语言是巨大的。与Python,Ruby,Perl和Java相比,C ++很小。用这些语言在stackoverflow上问一个基本问题,第一个答案几乎不可避免地是“为什么不导入SomeVeryBasicPackage并这样做呢?”。提出一个高级问题,第一个答案几乎不可避免地遵循“为什么不导入SomeMagicalPackage并做到这一点?”这样的思路。

–David Hammen
16年1月30日在19:52

@DavidHammen我认为80/20拆分是指核心语言功能,而不仅仅是标准库组件,在这种情况下,您提到的语言(可能是Perl除外)似乎并不像C ++那样大而复杂。无论如何,这只是我回答的很小一部分,我承认这是有偏见的。

–凯尔·斯特兰德(Kyle Strand)
16年1月30日在21:16

虚拟机/托管语言在表面上显然要复杂得多,但我的意思是从使用角度来看很复杂。

–凯尔·斯特兰德(Kyle Strand)
16年1月30日在21:18



我不知道您的理论是否正确,尽管就我而言,我肯定是分别学习了C ++和C,而且我的C ++类确实非常详尽。但是,关于20/80拆分的完整报价是,每个程序员都知道另一种20%的语言,而大多数程序员都不能通过单独学习C语言部分来解释。无论如何,如果您想详细解释C ++如何允许更健壮的编程(我声称我以前见过但不理解),我们最好在聊天室或其他方式而不是在这里进行评论。 。

–凯尔·斯特兰德(Kyle Strand)
16-10-2在21:11

#11 楼


假设我只能在项目环境中使用C ++。防止使用C ++具有但Java没有的某些语言功能是否很好(例如:多重继承,运算符覆盖)?


否。

如果“受项目环境”的限制,您只能使用C ++,那么即使考虑其他任何技术,也没有什么意义,无论您个人喜好/希望使用/扩展它。
“技术X”或“ Y”是否支持任何给定的功能,都与构建C ++应用程序的方式无关。
这是一个C ++应用程序,大概由于某些“正当理由”(现在或过去),因此您应该使用特定“工具箱”提供的内容将其编写为C ++应用程序。

如果并且有将应用程序移植到其他技术的要求,则(并且仅在那时)您可以考虑其他平台上的功能。可能发生某些事情的偶然机会是没有意义的“割鼻以恶作剧”。但是,请记住,批量重写是一项昂贵且有风险的操作,如果没有充分的理由,管理层不太可能进行重写。

几年前,在Visual Basic [.Net]世界中曾有过类似的辩论(“使用或不使用”),有人提出了一个聪明的主意,那就是您应该编写Visual Basic应用程序而不必使用Microsoft.VisualBasic命名空间提供的任何[核心语言]功能。这就像尝试编写没有std ::名称空间的C ++应用程序一样;好的,这是可能的,但是为什么在地球上任何有理智的人都愿意这样做呢?

评论


关于Visual Basic的最后一点:这些供应商库的问题在于它们是专有的。使用它们意味着将自己链接到该供应商。供应商会希望您被束缚,但是从长远来看,您不会:除非重写依赖于供应商特定功能的所有内容,否则您将无法使用其他供应商的软件。您使用供应商特定功能的次数越多,更换供应商的成本就越高,从而使您的供应商能够强制对您进行更改。这就是免费(如自由!)软件如此重要的原因之一。

–cmaster-恢复莫妮卡
16年1月25日在21:08

Microsoft.VisualBasic命名空间有点麻烦。自从我上次使用它已经有很多年了,但是至少在开始时,它主要是为了与VB6向后兼容(和/或使VB6程序员感到“在家”)。它主要以更现代(更好地集成)的形式提供了框架其余部分中已经可用的功能,因此在新项目中,很少使用它。相反,std ::名称空间是整个标准库所在的位置-避免它就像避免.NET中的整个BCL。

–马特奥(意大利)
16 Jan 28 '14:58



#12 楼

当前的回答都说这是一件不好的事情,因为您应该利用所使用的语言,并解释为什么C ++功能并不仅仅因为它不在jave中就“不好”。我将从另一个角度回答这个问题。

避免复杂的C ++功能(如多重继承,运算符重载和定义自己的模板)是一回事。

但是,除了完成最简单的任务之外,任何问题都无法解决:


分配内存,
将这些钱与积分连接起来
所以构建数据结构
然后在安全的情况下允许对内存进行重用

没有Java和C ++的通用子集可以实现上述目的,因此您所要求的是不可能的
(如果您询问Java和C#,您将有更多的机会,因为它们都使用垃圾收集器。)

但是您可能需要编写代码以便Java开发人员可以理解它的作用(但不能理解其详细的“操作方法”),这将是明智的。

您还可以设计自己的语言,以C ++和JAVA来实现。 。

#13 楼

没有人应该编写其他程序员不理解的任何代码。如果您认为语言锁定是个问题,请等到拥有开发人员锁定为止。一个人比另一个人更可能把你当作人质。

确实没有技术原因。您所创建的场景是出于某种原因使用某种语言的情况,但是许多当前甚至未来的开发人员并不能真正理解它。

我的猜测是,Java开发人员很可能会编写C ++他们用Java编写的方式,为什么要制定规则。您可能会发现一些C ++特定功能,这些功能对于Java开发人员来说只需一些C ++指令/文档,而不是他们原本会陷入的Java混乱局面。

关于BASIC程序员转向面向对象语言的问题的争论。并不是说他们实施OOP做法会损害那些不了解OOP的新开发人员,而是他们根本不会实施。如果这样做,通常会弄错。如果某件事做得不好,无论出于何种原因都需要将其删除。

除了盲目地复制和粘贴代码的人以外,他们还将在很多他们不了解的地方这样做。