为什么我们需要构造函数?

3
今天我的朋友问我,为什么在C++中需要构造函数?而在结构化语言中我们可以做同样的事情。构造函数有什么特殊之处?请向我展示为什么需要构造函数,以便我在我的C++程序中使用它。请帮助我并给我一些例子,这样我就能澄清他的疑虑。

8
为什么人们会雇用承包商为他们建房子呢?……因为这比自己动手来建更加简单。 - Marc B
你可以建议你的朋友尝试用汇编语言编写所有内容。 - Cascabel
@Marc B,您是说构造函数默认在对象创建时为类中的所有数据成员变量分配内存吗?默认构造函数的主体包含什么?编译器是否会向用户定义的构造函数注入任何隐藏代码?如果有,它是什么样子的?请解释一下。 - uss
7个回答

10

在同样的意义上,您不需要大多数流行语言的大多数功能一样,也不需要构造函数。

构造函数的存在是为了使做错误的事情更加困难。 在这种情况下,使用未初始化的数据。


1
同意。尽管 C++ 已经在过去的几十年中添加了自己的成熟功能,但值得记住的是,C++ 最初是作为 C 的预处理器而诞生的。构造函数就像你在 C 中编写的任何良好的 init 函数一样,但它们具有一流的语言支持,因此用户无需记住更多内容,因此使用仍然可能的两步初始化模式比较安全。这正是 C++ 之所以努力使用户生成的类型与内置类型表现相同的原因。不一致性越少,学习和使用就越容易。 - matthias
@Drew Dormann,您所说的“错误之物”是什么意思?请解释一下。 - uss
@sree 在这种情况下,“The Wrong Thing” 指的是使用尚未初始化的数据。 - Drew Dormann
@Drew Dormann,请提供更多关于“错误事项”的示例。 - uss
小注释:默认构造函数不会初始化对象。 - Svalbard
1
@Svalbard:“默认构造函数不会初始化对象” - 它会执行与任何构造函数一样的默认基类和成员初始化,并且不会初始化在类定义中显式赋值给的内置类型的数据成员,也不会初始化默认构造函数初始化列表中的数据成员。基本上,不提供自定义的默认构造函数是程序员表达对象的足够初始化的方式。 - Tony Delroy

3
一个极端的回答是,构造函数不会改变语言的图灵完备性,因此严格来说你不需要它们,就像你不需要语言的许多其他特性一样。但这只是形式上的,实际上构造函数非常有用。一个很好的实用例子是RAII模式。通过拥有构造函数,你可以将初始化和获取封装在同一个地方,同时也有了销毁。C语言没有构造函数,程序员经常忘记这个过程中的某些步骤,这是著名的问题。

3
正如其他人已经回答的那样,您可以像在过程式语言中使用init函数一样使用构造函数,但由于构造函数的存在,程序员不会忘记调用init函数——编译器会为他做到这一点。这带来的一个额外好处,除了自动调用它之外,还优雅地解决了继承初始化问题:对于一个扩展了类B、类B扩展了类C的类A而言,保证所有三个构造函数(类A,B和C)都将被调用,并且它们将按正确顺序调用(先是类C,然后是类B,最后是类A),以便每个构造函数都可以使用超类中的所有数据(因为它已经被初始化)。如果没有构造函数的语言,程序员将需要处理所有这些繁琐的工作。

0
在过程式语言中,您也需要将变量初始化为明确定义的值。通常使用某种类型的“Init”函数。构造函数是确保创建对象时它被初始化为有效状态的一种方式。
在.NET中,您可以绕过构造函数(使用特权代码),这样您将获得一个其字段已初始化为0的对象。

0

这就是面向对象语言的工作方式。在 C 语言中,您需要使用 malloc 来分配内存,然后以某种方式初始化该内存。而在 C++ 中,构造函数同时完成了这两个任务。将这两个任务结合起来,可以让开发人员更难分配内存并忘记或失败地初始化它。


0
因为有些对象需要数据来初始化。使用构造函数,您可以在编译时确保对象获取数据。否则,编译器会抛出错误。

0

不可变对象。

在并行或并发编程时,使用不能被改变的对象更容易共享。您不必担心竞争条件、锁等问题。但是,在大多数面向对象编程语言中,创建不可变对象的唯一方法是通过构造函数。您无法设置对象上的属性,因为根据定义,所有属性都是只读的。


但是如果你的对象是不可变的,那为什么它还是一个对象呢?(这个问题是关于C++的。) - reinierpost
你可能仍然需要功能,而该功能可能是多态的。例如,在WinRT中有只读列表接口,您可能希望在C++中实现它们。 - Jonathan Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接