在C#,C ++和Java中,当创建带有参数的构造函数时,默认的无参数函数将消失。我一直只是接受这个事实,但是现在我开始怀疑为什么。
这种行为的原因是什么?难道仅仅是“安全措施/猜测”这样的说法:“如果您创建了自己的构造函数,那么您可能不希望这种隐式结构徘徊”?还是出于技术原因,一旦您自己创建了构造函数,编译器就不可能添加一个?
Foo() = default;
恢复默认值了。
在C#,C ++和Java中,当创建带有参数的构造函数时,默认的无参数函数将消失。我一直只是接受这个事实,但是现在我开始怀疑为什么。
这种行为的原因是什么?难道仅仅是“安全措施/猜测”这样的说法:“如果您创建了自己的构造函数,那么您可能不希望这种隐式结构徘徊”?还是出于技术原因,一旦您自己创建了构造函数,编译器就不可能添加一个?
Foo() = default;
恢复默认值了。
Answers:
如果您添加了自己的构造器,则没有理由编译器无法添加构造器-编译器可以执行几乎所有需要的操作!但是,您必须查看最有意义的内容:
因此,在每种情况下,您都可以看到,就保留代码的可能意图而言,当前编译器的行为最有意义。
有肯定没有技术上的原因,为什么语言有被设计成这样。
我可以看到四个有点现实的选择:
选项1有点吸引人,因为我编写的代码越多,我真正想要无参数构造函数的频率就越少。有一天,我应该算刚刚多久我其实最终会使用一个默认的构造...
选项2我很好。
对于语言的其余部分,选项3违反了Java和C#的流程。除非明确计数使事情变得比Java默认情况下的私有程度要高,否则您绝不会明确“删除”任何内容。
选项4太可怕了-您绝对希望能够使用某些参数来强制构建。什么会new FileStream()
甚至意味着什么?
因此,基本上,如果您接受提供默认构造函数完全有意义的前提,那么我相信在您提供自己的构造函数后立即取消它是很有意义的。
struct
无论好坏,#4都是C#的情况。
编辑。实际上,虽然我在第一个答案中说的是正确的,但这是真正的原因:
最初有C。C不是面向对象的(您可以采用OO方法,但它无济于事或强制执行任何操作)。
然后是C With Classes,后来更名为C ++。C ++是面向对象的,因此鼓励封装,并确保对象的不变性-在构造时以及任何方法的开始和结束时,对象都处于有效状态。
这样做自然是要强制一个类必须始终具有构造函数以确保它以有效状态开始-如果构造函数不必执行任何操作来确保这一点,则空构造函数将记录此事实。
但是C ++的目标是尽可能地与C兼容,所有有效的C程序也都是有效的C ++程序(不再像目标那样活跃,而C向C ++的演进意味着它不再成立。 )。
这样做的效果之一是struct
和之间的功能重复class
。前者以C方式进行操作(默认情况下为所有公共),而后者以良好的OO方式(默认情况下为所有私有,而开发人员则主动将其想要公开的内容公开)。
另一个是为了使C struct
(由于C没有构造函数而不能具有构造函数)在C ++中有效,因此对于C ++来看待它的方式必须具有一定的意义。因此,尽管没有构造函数会违背OO确保主动确保不变式的做法,但C ++认为这意味着存在一个默认的无参数构造函数,其行为就像它具有一个空主体。
structs
现在所有C 都是有效的C ++ structs
(这意味着它们与C ++相同,classes
并且所有内容-成员和继承-公共)都从外部进行处理,就好像它具有单个无参数的构造函数一样。
但是,如果确实在class
或中放置了一个构造函数struct
,那么您将以C ++ / OO方式而不是C方式进行操作,则不需要默认的构造函数。
由于它是一种简写方式,因此即使无法实现兼容性,人们仍会继续使用它(它使用了C中没有的其他C ++功能)。
因此,当Java(以多种方式基于C ++)和后来的C#(以多种方式基于C ++和Java)出现时,他们保留了这种方法,因为编码人员可能已经习惯了这种方法。
Stroustrup在他的《 C ++编程语言》中写了这个,甚至更多,在《The Design and Evolution of C ++》中更加关注该语言的“为什么” 。
===原始答案===
假设这没有发生。
假设我不想要无参数构造函数,因为没有一个我就无法将我的类置于有意义的状态。确实,这struct
在C#中可能会发生(但是,如果您无法在C#中有意义地使用全零和空值struct
,那么您充其量只是在使用非公开可见的优化,否则会有一个使用中的设计缺陷struct
)。
为了使我的班级能够保护其不变性,我需要一个特殊的removeDefaultConstructor
关键字。至少,我需要创建一个私有的无参数构造函数,以确保没有调用代码调用默认值。
这使语言更加复杂。最好不要这样做。
总而言之,最好不要将添加构造函数视为删除默认值,而最好不要考虑完全不使用构造函数作为添加不执行任何操作的无参数构造函数的语法糖。
前提
这种行为可以视为类具有默认的公共无参数构造函数的决策的自然扩展。根据提出的问题,我们以该决定为前提,并假设在这种情况下我们没有对此提出质疑。
删除默认构造函数的方法
因此,必须有一种方法来删除默认的公共无参数构造函数。可以通过以下方式完成此删除:
选择最佳解决方案
现在我们问自己:如果没有无参数构造函数,则必须用什么代替?并且将我们想要在什么类型的场景删除默认的公共参数构造函数?
事情开始到位。首先,必须将其替换为带有参数的构造函数或非公共构造函数。其次,您不希望使用无参数构造函数的情况是:
结论
我们拥有了它-正是C#,C ++和Java允许删除默认的公共无参数构造函数的两种方式。
= delete
为此目的而引入的。
这是因为当您不定义构造函数时,编译器会自动为您生成一个不带任何参数的构造函数。当您希望从构造函数中获得更多东西时,您可以重写它。这不是函数重载。因此,编译器现在看到的唯一构造函数是带有参数的构造函数。为了解决此问题,如果不使用构造函数,则可以传递默认值。