2012-05-08 212 views
5

我见过很多代码,其中编码器为类定义了一个init()函数,并在创建实例后称其为第一件事。在构造函数中初始化

在构造函数中进行所有初始化是否有任何伤害或限制?

+2

为什么用Java和C++标记?商榷? –

+1

不,但有时会调用init在两个不同的构造函数之后初始化 - 以避免代码粘贴。 – Anycorn

+0

虚拟init()可以用于多态初始化 – vid

回答

0

它是有例外做一个设计模式从对象构造函数中抛出。

在C++中,如果从对象构造函数中抛出异常,那么该对象根据语言运行库被视为未构造。 因此,当对象超出范围时,不会调用对象析构函数。

这意味着,如果你有你这样的构造函数中的代码:

int *p1 = new int; 
int *p2 = new int; 

和这样的代码在你的析构函数:

delete p1; 
delete p2; 

P2初始化在构造函数中失败由于没有更多的可用内存,那么运算符新的运算符抛出bad_alloc异常。 此时,即使已正确分配了p1的内存,您的对象仍未完全构建。 如果发生这种情况,析构函数将不会被调用,并且正在泄漏p1。

因此,您在构造函数中放置的代码越多,发生错误的可能性就越大,从而导致潜在的内存泄漏。

这是设计选择的主要原因,毕竟这不是太疯狂。

更多关于这对香草萨特的博客:Constructors exceptions in C++

0

这是一个设计选择。你想让你的构造函数尽可能简单,所以很容易阅读它正在做什么。这就是为什么你会经常看到构造函数调用其他方法或函数,这取决于语言。它允许程序员阅读并遵循逻辑,而不会在代码中迷失方向。

随着构造函数的推出,您可以快速运行一个场景,您可以触发大量的事件。良好的设计决定了你将这些序列分解为更简单的方法,再次使它更易读,更容易维护。

所以,不,没有任何伤害或限制,这是一个设计偏好。如果你需要在构造函数中完成所有的初始化,那么在那里完成。如果您以后只需要它,请将其放入稍后调用的方法中。无论哪种方式,这完全取决于你,没有硬性规定或快速规则。

2

通常对于可维护性,减少代码大小,当多个构造函数调用相同的初始化代码:

class stuff 
{ 
public: 
    stuff(int val1) { init(); setVal = val1; } 
    stuff()   { init(); setVal = 0; } 

    void init()  { startZero = 0; } 

protected: 
    int setVal; 
    int startZero; 
}; 
1

在Java中,有充分的理由保持构造短,移动到init()方法初始化逻辑:

  • 构造函数不会被继承,所以任何子类都必须重新实现它们或提供与super
  • 你不应该调用构造函数重写的方法,因为你可以在一个不一致的状态找到你的目标在那里部分初始化
+0

你的两个参数似乎都反对使用'init()'方法。使用'super'清楚地表明你正在初始化基类,'init'可以被覆盖。事实上'init'可以在派生类中定义是一个非常强烈的反对在基类中使用它的论点。 –

2

正好相反:它通常是更好地把所有的初始化的 在构造函数中。在C++中,“最佳”策略通常是将 初始化设置在初始化程序列表中,以便成员使用正确的值直接构建,而不是构建默认的 ,然后分配。在Java中,您希望避免函数 (除非它是privatefinal),因为动态分辨率可以将 放入尚未初始化的对象中。

关于你使用init()函数的唯一原因是因为你的 有很多具有显着通用性的构造函数。 (在C++的情况下 ,你仍然必须权衡默认 建设,然后分配与使用 正确的值近期建设之间的差额。)

0

如果你有相同的类的多个对象或需要与指针被初始化为彼此,所以有指针的至少一个周期的不同类别依赖关系,你不能单独在构造函数中完成所有初始化。 (当另一个对象还没有被创建时,你将如何构造带有指向另一个对象的指针/引用的第一个对象?)

这种情况很容易发生的一种情况是在事件仿真系统中,其中不同的组件交互,以便每个组件都需要指向其他组件的指针。

由于无法在构造函数中完成所有初始化,因此至少有一些初始化必须在init函数中发生。这导致了一个问题:在init函数中应该完成哪些部分?灵活的选择似乎是在初始化函数中完成所有的指针初始化。然后,您可以按照任意顺序构造对象,因为在构建给定对象时,您不必担心是否已经有必要指向其他需要了解的对象。