在构造函数中初始化

时间:2012-05-08 07:08:05

标签: java c++ constructor initialization

我见过很多代码,编码器为类定义了一个 init()函数,并在创建实例后首先调用它。

在Constructor中进行所有初始化是否有任何损害或限制?

6 个答案:

答案 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 :(得分:2)

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

关于使用init()功能的唯一原因是因为您 有很多具有重要共性的构造函数。 (在这种情况下 对于C ++,你还需要权衡默认值之间的差异 建设,然后分配与立即建设与 正确的价值。)

答案 2 :(得分:1)

在Java中,有很好的理由让构造函数保持简短并将初始化逻辑转换为init()方法:

  • 构造函数不是继承的,因此任何子类都必须重新实现它们或提供与super链接的存根
  • 你不应该在构造函数中调用可覆盖的方法,因为你可以找到一个处于部分初始化状态的不一致状态的对象

答案 3 :(得分:0)

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

随着构造函数的发展,您可以快速遇到一个场景,在这个场景中,您希望触发大量事件。良好的设计要求您将这些序列分解为更简单的方法,再次使其更易读,更易于维护。

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

答案 4 :(得分:0)

这是一种设计模式,它与从对象构造函数内部抛出的异常有关。

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

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

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

和析构函数中的代码如下:

delete p1;
delete p2;
由于没有更多可用内存,

并且构造函数内的 p2 初始化失败,然后 new 运算符抛出bad_alloc异常。 此时,即使已正确分配 p1 的内存,您的对象也不会完全构建。 如果发生这种情况,则不会调用析构函数,并且您正在泄漏p1。

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

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

关于Herb Sutter博客的更多信息:Constructors exceptions in C++

答案 5 :(得分:0)

如果您有多个相同类或不同类的对象需要使用彼此指针进行初始化,那么至少有一个指针依赖循环,您不能单独在构造函数中进行所有初始化。 (当你还没有创建另一个对象时,你打算用另一个对象的指针/引用来构造第一个对象?)

容易发生这种情况的一种情况是在事件模拟系统中,不同的组件会相互作用,因此每个组件都需要指向其他组件的指针。

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