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

时间:2012-08-03 08:38:05

标签: c# java c++ default-constructor

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

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

11 个答案:

答案 0 :(得分:218)

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

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

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

答案 1 :(得分:68)

语言 以这种方式设计肯定没有技术上的原因。

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

  1. 根本没有默认构造函数
  2. 当前情况
  3. 始终默认提供默认构造函数,但允许明确禁止它
  4. 始终提供默认构造函数,不允许禁止
  5. 选项1有点吸引人,因为我编码越多,我真正想要无参数构造函数的频率越低。有一天,我应该算一下我实际最终使用默认构造函数的频率......

    选项2我很好。

    对于语言的其余部分,选项3违背了Java和C#的流程。从来没有任何明确“删除”的东西,除非你明确指出比Java中默认的更私密。

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

    所以基本上, if 你接受提供默认构造函数的前提是有意义的,我相信一旦你提供自己的构造函数就很有意义地压制它。

答案 2 :(得分:19)

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

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

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

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

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

这样做的一个影响是structclass之间的功能重复。前者以C方式处理(默认情况下一切都是公开的),后者以良好的OO方式处理(默认情况下一切都是私有的,开发人员主动公开他们想要公开的内容)。

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

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

但是,如果您确实将构造函数放在classstruct中,那么您使用的是C ++ / OO方式而不是C方式,并且不需要默认构造函数。

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

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

Stroustrup在他的 The C ++ Programming Language 中写到了这一点,更加关注 C ++的设计和演变中语言的“为什么”

===原始答案===

让我们说这没有发生。

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

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

这使语言复杂化了。最好不要这样做。

总之,最好不要考虑添加构造函数作为删除默认值,最好不要考虑没有构造函数作为语法糖来添加无参数的构造函数。

答案 3 :(得分:13)

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

如果不是这种方式,如果只希望通过带参数的构造函数构造对象,则需要一些禁用默认构造函数的显式方法。

答案 4 :(得分:3)

我认为问题应该是另一种方式:如果你没有定义任何其他构造函数,为什么不需要声明默认构造函数?

非静态类必须使用构造函数 所以我认为如果你还没有定义任何构造函数,那么生成的默认构造函数只是C#编译器的一个方便特性,如果没有构造函数,你的类也是无效的。因此,隐式生成不执行任何操作的构造函数没有错。它看起来比拥有空构造函数更清晰。

如果您已经定义了构造函数,那么您的类是有效的,那么为什么编译器会假设您需要一个默认构造函数?如果你不想要一个怎么办?实现一个属性来告诉编译器不生成那个默认构造函数?我认为这不是一个好主意。

答案 5 :(得分:3)

这是编译器的便利功能。 如果使用参数定义构造函数但未定义无参数构造函数,则不希望允许无参数构造函数的可能性要高得多。

对于许多使用空构造函数初始化没有意义的对象就是这种情况。

否则,您必须为要限制的每个类声明一个私有的无参数构造函数。

在我看来,为需要参数的类提供无参数构造函数并不好。

答案 6 :(得分:1)

只有当类没有构造函数时,才能构造默认构造函数。编译器的编写方式只是将其作为备份机制提供。

如果您有参数化构造函数,则可能不希望使用默认构造函数创建对象。如果编译器提供了默认构造函数,则必须编写一个无参数构造函数并将其设置为私有,以防止使用无参数创建对象。

此外,您忘记禁用或“私有化”默认构造函数的可能性会更高,从而导致潜在的功能错误难以捕获。

现在,如果您希望以默认方式或通过传递参数创建对象,则必须显式定义无参数构造函数。这是强烈检查的,编译器会另外抱怨,从而确保这里没有漏洞。

答案 7 :(得分:1)

<强>前提

此行为可视为决定类的自然扩展,以使类具有默认的无参数构造函数。根据被问到的问题,我们将此决定作为前提,并假设我们在这种情况下不会质疑它。

删除默认构造函数的方法

接下来必须有一种方法来删除默认的public parameterless构造函数。这种删除可以通过以下方式完成:

  1. 声明非公共无参数构造函数
  2. 当声明带参数的构造函数
  3. 时,自动删除无参数构造函数
  4. 一些关键字/属性,用于指示编译器删除无参数构造函数(不够容易排除)
  5. 选择最佳解决方案

    现在我们问自己:如果没有无参数构造函数,那么必须将它替换为什么?在什么类型的场景下我们要删除默认的无参数构造函数?< / em>的

    事情开始落实到位。首先,它必须用带参数的构造函数替换,或者用非公共构造函数替换。其次,您不需要无参数构造函数的场景是:

    1. 我们根本不想要实例化类,或者我们想要控制构造函数的可见性:声明非公共构造函数
    2. 我们希望强制在构造时提供参数:声明带参数的构造函数
    3. <强>结论

      我们有它 - 正是C#,C ++和Java允许删除默认公共无参数构造函数的两种方式。

答案 8 :(得分:1)

我认为这是由编译器处理的。如果在.net中打开ILDASM程序集,您将看到默认构造函数,即使它不在代码中。如果定义参数化构造函数,则不会看到默认构造函数。

实际上,当您定义类(非静态)时,编译器会提供此功能,以为您将只创建一个实例。如果你想要执行任何特定的操作,你肯定会拥有自己的构造函数。

答案 9 :(得分:0)

因为当你没有定义构造函数时,编译器会自动为你生成一个不带任何参数的构造函数。如果你想要更多的构造函数,你可以覆盖它。这不是函数重载。所以编译器现在看到的唯一构造函数是你的构造函数,它接受一个参数。要解决此问题,如果构造函数没有传递值,则可以传递默认值。

答案 10 :(得分:0)

一个类需要一个构造函数。这是强制性要求。

  • 如果您不创建一个,则将自动为您提供无参数的构造函数。
  • 如果您不需要无参数的构造函数,则需要创建自己的构造函数。
  • 如果同时需要无参数构造函数和基于参数的构造函数,则可以手动添加它们。

我将用另一个答案回答您,为什么我们总是要使用默认的无参数构造函数?在某些情况下,这是不希望的,因此开发人员可以根据需要控制添加或删除它。