![]() |
1
71
既然他们说“计时”,我猜是因为他们希望自己的init函数能够调用对象上的虚函数。这并不总是在构造函数中起作用,因为在基类的构造函数中,对象的派生类部分“还不存在”,尤其是不能访问派生类中定义的虚拟函数。相反,如果已定义,则调用函数的基类版本。如果没有定义(意味着函数是纯虚拟的),则会得到未定义的行为。 使用init函数的另一个常见原因是希望避免异常,但这是一种非常古老的编程风格(这是否是一个好主意完全取决于它自己)。它与不能在构造函数中工作的东西无关,而是与如果某个东西失败,构造函数不能返回错误值这一事实有关。既然你的同事给了你真正的理由,我想这不是原因。 |
![]() |
2
33
是的,我能想到几个,但总的来说这不是个好主意。
然而,在正确设计的OO代码中,构造函数负责建立类不变量。通过允许一个默认构造函数,您就允许一个空类,因此您必须修改不变量,这样“null”类和“有意义”类都可以接受。。。每次使用类都必须首先确保对象已正确构建。。。太粗鲁了。 那么现在,让我们揭穿“理由”:
|
![]() |
3
17
其他人列出了许多可能的原因(以及为什么这些通常不是好主意的适当解释)。我来举一个例子 . 在以前的一个项目中,我们有很多服务类和对象,它们都是层次结构的一部分,并且以各种方式相互交叉引用。因此,通常,为了创建ServiceA,您需要一个父服务对象,而父服务对象又需要一个服务容器,该容器在初始化时已经依赖于某些特定服务(可能包括ServiceA本身)的存在。原因是,在初始化过程中,大多数服务向其他服务注册,作为特定事件的侦听器,和/或向其他服务通知初始化成功的事件。如果在发出通知时另一个服务不存在,则注册不会发生,因此该服务在应用程序使用期间不会在以后接收重要消息。为了 打破循环依赖链 ,我们必须使用独立于构造函数的显式初始化方法,因此 使全局服务初始化成为一个两阶段的过程 . 因此,虽然这个成语不应该被普遍遵循,但它有一些有效的用法。但是,最好将其使用限制到最低限度,尽可能使用构造函数。在我们的例子中,这是一个遗留项目,我们还没有完全理解它的体系结构。至少init方法的使用仅限于服务类-常规类是通过构造函数初始化的。我相信有一种方法可以重构该体系结构,以消除对服务初始化方法的需求,但至少我没有看到如何做到这一点(坦率地说,在我参与项目时,我们有更紧迫的问题要处理)。 |
![]() |
4
8
有两个原因我想得很清楚:
|
![]() |
5
5
可以在对象池中再次使用这种初始化。基本上,您只需从池中请求对象。该池将已经创建了一些空的N个对象。现在是调用者可以调用他/她喜欢的任何方法来设置成员。一旦调用者处理完对象,它就会告诉池销毁它。这样做的好处是,在对象被使用之前,内存将被保存,调用者可以使用自己合适的成员方法初始化对象。一个对象可能有很多用途,但调用者可能不需要全部,也可能不需要初始化对象的所有成员。
|
![]() |
6
5
当编译器不支持异常,或者目标应用程序不能使用堆(通常使用堆来创建和销毁异常)时,init()函数是很好的。 当需要定义构造顺序时,init()例程也很有用。也就是说,如果全局分配对象,则不会定义调用构造函数的顺序。例如:
本标准不保证 的构造函数将在 实例1 的构造函数。当它与硬件联系在一起时,事物初始化的顺序是至关重要的。 |
![]() |
7
1
我还想附上一个代码样本来回答#1-- 因为msdn也说:
例子: 下面的示例演示了违反此规则的效果。测试应用程序创建DerivedType的实例,从而执行其基类(BadlyConstructedType)构造函数。BadlyConstructedType的构造函数错误地调用了虚拟方法DoSomething。如输出所示,衍生型剂量测定法()执行,并在DerivedType的构造函数执行之前执行。
输出:
导出的剂量测量称为-初始化?不
|
![]() |
8
1
更特殊的情况是:如果您创建了一个侦听器,您可能希望让它在某个地方注册自己(例如使用单例或GUI)。如果在构造函数中这样做,它会泄漏一个指向自身的指针/引用,这还不安全,因为构造函数还没有完成(甚至可能完全失败)。 假设singleton收集所有侦听器,并在发生事件时向它们发送事件receives和event,然后循环遍历侦听器列表(其中一个就是我们正在讨论的实例),向每个侦听器发送一条消息。但是这个实例在其构造函数中仍然处于中间位置,因此调用可能会以各种不好的方式失败。在这种情况下,将注册放在一个单独的函数中是有意义的,您显然是这样做的 从构造函数本身调用(这将完全破坏目的),但在构造完成后从父对象调用。 但这是一个具体的情况,而不是一般的情况。 |
|
9
1
|
![]() |
10
0
还有几个案例:
例如,假设我们有一个初始值设定项,它接受一个常规arg的列表。我们有另一个初始值设定项,它接受一个名=值对的字典。第二个可以在字典中查询第一个初始值设定项接受的参数,并用它们调用第一个参数。 当初始值设定项是init方法时,这很好,但当初始值设定项是构造函数时则不行。 鸡肉还是鸡蛋 我们可能有一个car类,其初始值设定项必须有一个指向motor对象的指针,motor类初始值设定项必须有一个指向其car对象的指针。这对于构造函数来说是不可能的,但是对于init方法来说却是微不足道的。 分解ARG列表 可能有大量的arg 能够 同样,分解一个构造函数是不可能的,但分解一个初始值设定项是微不足道的。 |
![]() |
11
-2
如果在创建类之后需要调用初始化器,则可以使用初始化方法而不是构造函数。因此,如果类A被创建为:
|
![]() |
rookie · 检查函数模板的所有参数包参数是否属于int 1 年前 |
![]() |
ivaigult · -W转换和隐式字符串到布尔类型转换 1 年前 |
![]() |
rainer · 后台插入程序的初始化 1 年前 |
![]() |
Community wiki · 以理智、安全和高效的方式复制文件 1 年前 |
|
Shefali Kanaujia · 对C中向量的向量进行排序++ 1 年前 |
|
Ma Joonyoung · 粗粒度和细粒度链表的时间比较 1 年前 |