初始化班级成员的更好做法是什么?

时间:2018-08-28 09:25:20

标签: c++ c++17

假设我有一个看起来像这样的A类:

class A {
public:
  public A(bool someFlag, Params someParams);
private:
  vector<string> texts;
}

我想提取初始化texts成员字段的逻辑。 我提出了两个想法:

  1. 第一个想法-静态的私有成员函数,可以返回所需的文本向量。

    A::A(bool someFlag, Params someParams) {
      if (someFlag)
        texts = createSomeTexts(someParams);
      else
        texts = createOtherTexts(someParams);
    }
    
  2. 第二个想法-私有成员函数,可以自行分配给类成员所需的文本向量。

    A::A(bool someFlag, Params someParams) {
      if (someFlag)
        createAndAssignSomeTexts(someParams);
      else
        createAndAssignOtherTexts(someParams);
    }
    

当然,两个版本都能正确完成工作,但是我想知道针对这些情况的建议方法是什么。另外,如果成员初始化需要更多参数(尤其是作为成员存储在类中的参数),方法是否应该更改。

2 个答案:

答案 0 :(得分:8)

您应该努力初始化您的数据成员,而不是在构造函数主体中分配给它们。您显示的两个版本都会导致std::vector<std::string>实例的默认构造,并在以后分配给它。因此,我建议这样做:

A::A(bool someFlag, const Params& someParams) :
    texts(someFlag ? createSomeTexts(someParams) : createOtherTexts(someParams))
{}

或更容易理解的是,让createSomeTexts也处理该标志:

A::A(bool someFlag, const Params& someParams) :
    texts(createSomeTexts(someFlag, someParams))
{}

如果createSomeTexts需要访问其他数据成员,则使其成为成员函数(确保在texts成员之前声明它们并正确初始化-正如@Scheff所指出的那样,这不太可能一个好主意)。否则,使其成为自由函数(请参阅here,为什么这是可取的)。一旦createSomeTexts是一个自由函数,您同样可以像这样构造对象:

std::vector<std::string> stringsToInject = createSomeText(/* Some flags.... */);

A instance(stringsToInject); // A's ctor updated to make this work 

由于A的构造函数负责初始化数据成员,而创建初始化数据的逻辑位于其他地方,因此这可能会进一步分散关注点。

答案 1 :(得分:2)

我将使用情况1,因为函数createSomeTexts和createOtherTexts不会更改任何类变量。这意味着这些功能可以进行单元测试。

最好不要使用全局变量,如果必须的话,不要从全局范围(this->)更改它们,而应通过引用或将其作为指向函数的指针来传递。 这样,您可以在代码中传递存根并编写测试用例。

此外,Params应该是const引用:

class A {
  public:
    public A(const bool someFlag, const Params &someParams);
private:
  vector<string> texts;
}