如何在派生类中存储基类初始化期间获得的信息?

How can I store in a derived class information obtained during initialization of a base class?

提问人:sbi 提问时间:2/25/2014 最后编辑:sbi 更新时间:2/25/2014 访问量:112

问:

我遇到的情况是,作为提供数据来初始化基类的副作用,派生类会计算一条信息,这些信息以后必须通过其接口提供。下面给出了问题的概念,使用布尔值作为所需的信息:

class base {
public:
  base(some_initialization_data);
  // ... 
};

class derived : public base {
public:
  derived()
  : base(calc_init_data())
  {
  }

  bool condition_x_occurred() const
  {
    // How to get at the information obtained 
    // during the call to calc_init_data()? 
  }
private:
  static some_initialization_data calc_init_data()
  {
    // This piece of information will later be needed: 
    const bool condition_x_occurred = /* ... */;
    return some_initialization_data(condition_x_occurred);
  }
};

这样做的问题在于,在初始化派生类自己的数据成员之前,在基类初始化期间计算了重要的信息。因此,我还不能写入派生类的数据元素。虽然我确信我可以摆脱过去 20 年中我遇到的任何平台上尚未正式创建的布尔值,但我希望避免调用未定义的行为。

请注意,所讨论的信息与基类完全无关,因此无法将其存储在基类中。此外,信息不能存储在静态数据成员中。我有一些关于如何重构代码的想法,以便我可以做到这一点,但是对于这样一个小问题,我能想出的那些似乎都非常具有侵入性。所以我想知道你们中的一个人能不能想出一些简单的东西?


注意:由于我们使用的是嵌入式平台,因此我们只能使用 GCC 4.1.2。所以严格使用 C++03(包括 TR1),但没有 C++11。

C++ 重构 初始化顺序

评论

2赞 Angew is no longer proud of SO 2/25/2014
听起来像是boost::base_from_member可以解决的问题。
0赞 sbi 2/25/2014
@Angew:潜入另一个基类也是我最喜欢的解决方案,尽管我觉得它有点侵入性。我不知道boost有这个功能,觉得它很有趣。但是,我不确定使用它而不是简单的基类是否使您的代码更易于阅读和维护。不过,我可能会尝试一下。你为什么不把这个作为答案呢?它值得点赞。
0赞 Angew is no longer proud of SO 2/25/2014
我从未使用过它,所以我不能自信地在答案中发布示例。而且我不喜欢仅链接的答案。

答:

2赞 Jarod42 2/25/2014 #1

在 C++11 中,您可以执行如下操作:

class derived : public base {
public:
  derived() : derived(calc_init_data()) {}

  bool condition_x_occurred() const { return my_condition_x_occurred; }

private:
    derived(const std::pair<bool, some_initialization_data>& p) :
        base(p.second), my_condition_x_occurred(p.first)
    {}

  static std::pair<bool, some_initialization_data> calc_init_data()
  {
    // This piece of information will later be needed:
    const bool condition_x_occurred = /* ... */;
    return std::make_pair(condition_x_occurred, some_initialization_data(condition_x_occurred));
  }

private:
    bool my_condition_x_occurred;
};

在 C++03 中,可以将派生类更改为:

class derived : public base {
public:
  static derived make_derived() { return derived(calc_init_data()); }

  bool condition_x_occurred() const { return my_condition_x_occurred; }

private:
    derived(const std::pair<bool, some_initialization_data>& p) :
        base(p.second), my_condition_x_occurred(p.first)
    {}

  static std::pair<bool, some_initialization_data> calc_init_data()
  {
    // This piece of information will later be needed:
    const bool condition_x_occurred = /* ... */;
    return std::make_pair(condition_x_occurred, some_initialization_data(condition_x_occurred));
  }

private:
    bool my_condition_x_occurred;
};

评论

0赞 sbi 2/25/2014
对不起,我忘了提到我们被困在 C++03 上。根本没有 C++11。这也是基于委派 ctors。这很好,因为它采用了.另一个来自我。std::pair+1
0赞 Jarod42 2/25/2014
您可以使用工厂(伪造委托构造函数)吗?
0赞 sbi 2/25/2014
是的,我可以。但是,这属于“相当侵入性”。:-/
0赞 Jarod42 2/25/2014
请参阅我的编辑(但@hansmaad的默认参数解决方案似乎更好)。
2赞 hansmaad 2/25/2014 #2

如果编译器上可用,则可以使用委托构造函数:

struct derived_init
{
    bool data;
    some_initialization_data calc()
    {
        data = true;
        return some_initialization_data();
    }
};


class derived : public base {
public:
    derived()
        : derived(derived_init{})
    { }

    bool condition_x_occurred() const
    {
        return init_data.data;
    }
private:
    derived(derived_init init)
        : base(init.calc()), init_data(init)
    { }
    derived_init init_data;
};

使用 C++03,您可以使用默认参数:

class derived : public base {
public:
    derived(derived_init init = derived_init{})
        : base(init.calc()), init_data(init)
    {
    }
private:
    derived_init init_data;
};

评论

0赞 sbi 2/25/2014
对不起,我忘了提到我们被困在 C++03 上。这里没有委派 ctor。 不过,不错的解决方案,非常不打扰。 从我这里。:(+1
0赞 hansmaad 2/25/2014
@sbi 也许默认参数对你来说没问题?请参阅编辑。