为什么默认的无参数构造函数在创建带参数的构造函数时会消失

ola*_*gjo 160 c# c++ java default-constructor

在C#,C++和Java中,当您创建一个使用参数的构造函数时,默认的无参数函数就会消失.我一直都接受这个事实,但现在我开始想知道为什么.

这种行为的原因是什么?它只是一个"安全措施/猜测"说"如果你已经创建了自己的构造函数,你可能不希望这个隐含的构造函数"?或者它是否有技术原因使得编译器在您自己创建构造函数后无法添加一个?

Dan*_*zey 219

如果你已经添加了自己的编译器,编译器就没有理由不添加构造函数 - 编译器可以做任何想做的事情!但是,你必须看看最有意义的东西:

  • 如果我没有为非静态类定义任何构造函数,我很可能希望能够实例化该类.为了允许这种情况,编译器必须添加一个无参数构造函数,它不会影响实例化.这意味着我不必在代码中包含一个空构造函数,只是为了使它工作.
  • 如果我已经定义了我自己的构造函数,特别是带有参数的构造函数,那么我很可能拥有自己的逻辑,必须在创建类时执行.如果编译器在这种情况下创建一个空的无参数构造函数,它将允许某人跳过我编写的逻辑,这可能导致我的代码以多种方式中断.如果我想在这种情况下使用默认的空构造函数,我需要明确说明.

因此,在每种情况下,您都可以看到当前编译器的行为在保留代码的可能意图方面最有意义.

  • @KonradRudolph,第一句话说编译器*可以*在这个场景中添加一个构造函数 - 其余的答案解释了为什么它没有(对于问题中指定的语言) (76认同)
  • 我认为你的其余答案几乎证明了你的第一句错误. (2认同)

Jon*_*eet 69

有肯定没有技术上的原因,为什么语言被设计成这样.

我可以看到有四个有点现实的选项:

  1. 根本没有默认构造函数
  2. 目前的情况
  3. 默认情况下始终提供默认构造函数,但允许显式抑制它
  4. 始终提供默认构造函数不允许它被抑制

选项1有点吸引人,因为我编写的代码越少,我真正想要一个无参数构造函数.有一天,我应该算一下我实际上最终使用默认构造函数的频率......

选项2我很好.

对于语言的其余部分,选项3违背了Java和C#的流程.从来没有任何明确"删除"的内容,除非你明确指出比Java中默认情况更私密.

选项4很糟糕 - 你绝对希望能够用某些参数强制构造.什么会new FileStream()甚至意味着什么?

所以基本上,如果你接受提供默认构造函数的前提是有意义的,我相信只要你提供自己的构造函数就可以很好地压制它.

  • @PetrMensik:如果你的无参数构造函数真的不需要做任何事情,它就是一个单行代码,肯定不会比"显式删除"语句需要更多的代码. (8认同)
  • 我喜欢选项1,因为它更容易理解.没有你在代码中看不到的"魔法"构造函数.对于选项1,编译器应该在(或者甚至不允许?)非静态类没有实例构造函数时发出warnig.怎么样:"没有找到类<TYPE>的实例构造函数.你的意思是声明类静态吗?" (4认同)
  • @PetrMensik:对不起,我的错,是的.这绝对与我的经历相反 - 而且我认为自动包含某些东西也是更危险的*选项......如果你不小心最终没有排除它,你可以搞砸你的不变量等等. (2认同)
  • #4是C#`struct的情况,无论好坏. (2认同)

Jon*_*nna 19

编辑.实际上,虽然我在第一个答案中说的是有效的,但这才是真正的原因:

在开始时有C. C不是面向对象的(你可以采用面向对象的方法,但它不会帮助你或执行任何东西).

然后是C With Classes,后来改名为C++.C++是面向对象的,因此鼓励封装,并确保对象的不变性 - 在构造时以及在任何方法的开始和结束时,对象处于有效状态.

自然要做的是强制一个类必须始终有一个构造函数来确保它以有效状态启动 - 如果构造函数不必做任何事情来确保这一点,那么空构造函数将记录这个事实.

但是C++的目标是与C兼容,以便尽可能地使所有有效的C程序都是有效的C++程序(不再是活跃的目标,而C语言与C++的分离意味着它不再成立).

其中一个影响是struct和之间的功能重复class.前者以C方式处理(默认情况下一切都是公开的),后者以良好的OO方式处理事务(默认情况下一切都是私有的,开发人员主动公开他们想要公开的内容).

另一个原因是,为了使C struct(由于C没有构造函数而没有构造函数)在C++中有效,因此必须有一个C++方式来看待它的含义.因此,虽然没有构造函数会违反主动确保不变量的OO实践,但C++认为这意味着有一个默认的无参数构造函数,就像它有一个空体.

所有C structs现在都是有效的C++ structs(这意味着它们与C++相同classes,所有内容 - 成员和继承 - 公共)从外部处理,就像它有一个无参数构造函数一样.

但是,如果你确实在一个classor中放置了一个构造函数struct,那么你就是用C++/OO方式而不是C方式做事,并且不需要默认的构造函数.

由于它是一种速记,即使在兼容性不可能的情况下,人们仍然继续使用它(它使用的不是C中的其他C++特性).

因此,当Java出现(在很多方面基于C++)和后来的C#(以不同方式基于C++和Java)时,他们将这种方法保留为编码器可能已经习惯的东西.

Stroustrup在他的C++编程语言中写到了这一点,甚至更多地关注C++设计和演化中语言的"原因" .

===原始答案===

让我们说这没有发生.

假设我不想要一个无参数构造函数,因为如果没有一个构造函数我就无法将其置于有意义的状态.实际上,这是structC#中可能发生的事情(但是如果你不能在C#中有意义地使用全零和空值struct,那么你最好使用非公开可见的优化,否则就有了使用中的设计缺陷struct).

为了使我的类能够保护其不变量,我需要一个特殊的removeDefaultConstructor关键字.至少,我需要创建一个私有的无参数构造函数,以确保没有调用代码调用默认值.

这使语言复杂化了一些.最好不要这样做.

总而言之,最好不要将构造函数添加为删除默认值,最好不要将构造函数视为添加无参数构造函数的语法糖.


And*_*bel 13

如果您不自行执行任何操作来控制对象创建,则会添加默认的无参数构造函数.一旦你创建了一个构造函数来控制,编译器就会"退避"并让你拥有完全的控制权.

如果它不会是这样,你需要禁用默认构造函数的一些明确的方式,如果你只想对象通过一个带参数的构造函数是施工的.

  • 那不一样.该类的任何方法(包括静态方法)都可以调用它.我更喜欢让它完全存在. (5认同)