C ++重构:构造函数中的初始化排序

时间:2011-10-20 11:18:36

标签: c++ constructor initializer

假设我需要在构造函数初始化任何成员变量之前调用一个空闲的GlobalInitializer()。例如:

class Foo {
  public:
    Foo() : bar_()
    {
      // calling GlobalInitializer() here is too late
    }
  Bar bar_;
};

在Foo中调用GlobalInitializer()为时已晚,因为我需要在bar_初始化之前调用它。我的hacky解决方法是创建一个超级班:

class MyInitializer {
  protected:
    MyInitializer() {
      GlobalInitializer();
    }
};
class UglyFoo : public MyInitializer
{
  public:
    UglyFoo() : bar_()
    { }
  Bar bar_;
};

UglyFoo完成了工作,但它需要这个丑陋的MyInitializer类。是否有更清洁的设计模式或重构可以达到相同的效果?

附加说明:GlobalInitializer()是一项昂贵的调用,除非用户实例化Foo(),否则我要避免这种调用。 GlobalInitializer()内部有针对多个调用的警卫。此外,可能还有其他类,比如说FooBar,也需要调用GlobalInitializer(),但在一个进程中,GlobalInitializer()实际上会工作一次(如果实例化Foo或FooBar)或者甚至不执行一次(如果没有) Foo或FooBar的实例化。

5 个答案:

答案 0 :(得分:4)

class Foo {
private:
    struct Initializer {
        Initializer() { GlobalInitializer(); }
    };
    Initializer initializer__;  // declare before bar__ to ensure it is constructed first

public:
    Foo() : bar_()
    {
    }

    Bar bar_;
};

答案 1 :(得分:1)

你应该重新思考你的设计。

好的设计意味着loose-coupling。如果您的对象创建依赖于不同的方法调用,那么就会出现严重错误。

如果你确实需要这个,你应该在GlobalInitializer的构造函数中调用bar_,但最好的方法是重新考虑你的设计。

答案 2 :(得分:0)

你所做的事情似乎违反了面向对象的价值观,因为你的课程不合理地依赖于他们之外的东西;我建议你重新设计你的课程以避免这种情况。

话虽这么说,一个适合你的设计模型但不让每个类继承另一个类的选项是将MyInitializer类创建为单例对象,并为依赖于这个初始化的每个类添加一个MyInitializer。单例只会在第一次实例化时执行初始化。

答案 3 :(得分:0)

据推测,你可以重构任何GlobalInitializer初始化不再是全局的。然后,您可以选择如何为您的班级提供数据。你知道,因为globals are bad和所有。

答案 4 :(得分:0)

在梦中找到我:将bar_改为指针:

class Foo {
  public:
    Foo()
    {
      GlobalInitializer();
      // now we can call GlobalInitializer() in time
      bar_ = new Bar; 
    }
    ~Foo()
    {
      delete bar_;
    }

  private:
    Bar* bar_;
};