【问题标题】:Is there an alternative to initializer lists?初始化列表是否有替代方案?
【发布时间】:2018-03-16 10:42:17
【问题描述】:

我有 SmallClassBigClass 的课程。 BigClass 作为 SmallClass 的对象的私有属性。我读过初始化列表,但问题是我无法预测需要传递给SmallClass 的构造函数的值。代码如下所示:

class SmallClass {
  public:
    SmallClass(int);
  private:
    int boo;
}

SmallClass::SmallClass(int i) {
  boo = i;
}

class BigClass {
  public:
    BigClass();
  private:
    SmallClass sc; // I guess this calls the constructor (and does not compile)
};

BigClass::BigClass() {
  int foo;
  /* Do stuff. I end up with a "foo" having a non predictable value. */
  sc = SmallClass(foo); /* Is there a way to do something like this? */
}

【问题讨论】:

  • 什么是do stuff?而为什么foo的计算不能进入does stuff的小效用函数呢?
  • @StoryTeller 我能想到一个例子——BigClass ctor 调用一些外部 API,返回 foobar,我们想将 foo 传递给 SmallClass 和 @987654335 @别处
  • @Kos - 这一切都很好。但这是 OP 需要包含的一个细节,让人们知道他们最好避免沿着这些思路回答。为每个人节省不少时间(包括 OP)。
  • 您是否尝试过创建一个“做事”的函数,然后在初始化列表中为SmallClass 构造函数调用它?喜欢BigClass::BigClass() : sc(DoStuff()) {}
  • @StoryTeller 抱歉,如果问题缺少上下文。我试图将它与我正在尝试的完全隔离。 BigClass 有更多成员,其中一个是一个对象,其状态在BigClass 的构造函数中以随机方式改变(就像一副纸牌)。事情就在设置foo 的值之前,我需要读取所述纸牌的状态(并在读取时更改它)。

标签: c++ object constructor initialization initializer-list


【解决方案1】:

初始化列表有替代方案吗?

是的。默认成员初始化器是初始化器列表的替代方案。但是,这对您的情况没有用。事实上,它只有在构造函数的参数可预测时才有用。

foo 的“不可预测性”对于初始化点亮不是问题;你不需要替代品。只需调用一个函数:

int get_foo() {
    int foo;
    /* Do stuff. I end up with a "foo" having a non predictable value. */
    return foo;
}

BigClass::BigClass() : sc(get_foo()) {}

如果“do stuff” 包括对成员的访问(示例中没有其他成员,我假设它可能是一种简化),那么您可以使用成员函数来实现这一点。但是请记住,您只能访问在 sc 之前初始化的成员。

【讨论】:

  • “如果 'do stuff' 包括对成员的访问,那么您可以使用成员函数来实现。” - 呃,不,你不能。我的意思是,如果允许未定义的行为,您可以。否则,在运行 c'tor 之前调用访问成员数据的成员函数将不会顺利结束。
  • @IInspectable 在构造函数(包括成员初始化器列表)中访问成员或调用成员函数不是UB。但是您确实需要注意只访问已经初始化的成员。
  • 这还不完整。如果你提议调用成员函数来访问非静态类成员,你将不得不解释,在调用get_foo()之前初始化了哪些类成员。
  • @IInspectable 再说一遍,我所有的答案都不完整,因为我没有描述整个 C++ 语言。我提到了成员访问,因为它可能并不明显。我现在提到必须初始化成员,因为这可能会被忽略。但是我发现很明显,要找出初始化了哪些成员,程序员必须知道初始化的顺序。我相信在 SO 上存在一个单独的问题和答案。
【解决方案2】:

我建议一个解决方法:

class SmallClass 
{
public:
    SmallClass();
public:
    void SetBoo(int value);
private:
    int boo;
};

SmallClass::SmallClass() 
{
    boo = 0;
}

void SmallClass::SetBoo(int value) 
{
    boo = value;
}

class BigClass 
{
public:
    BigClass();
private:
    SmallClass sc; // I guess this calls the constructor (and does not compile)
};

BigClass::BigClass() 
{
    int foo;
    /* Do stuff. I end up with a "foo" having a non predictable value. */
    sc.SetBoo(foo); /* Yes, you can set the boo member */
}

【讨论】:

  • 我认为 cmets 中已经建议的解决方法更好。
  • 当我写我的解决方法时,什么也没写。顺便说一句,你可以想你想要的。
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
  • 2014-10-06
  • 2023-03-17
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多