使用派生 class 成员初始化父 class

Using derived class members for the initialization of the parent class

我想初始化一个从 class A 派生的 class B,然后在 B 中我首先构造一个缓存用于 A 的构造,例如

class B: public A {

public:
  B(): A(cache_), cache_(this->buildCache_())

protected:
  const SomeDataType cache_;

private:
  SomeDataType
  buildCache_() const
  {
    // expensive cache construction
  }

}

不会 起作用,因为父对象 A 总是首先初始化(在 cache_ 被填充之前)。

(为了完整起见:cache_B 派生的 class 中使用了很多次。)

作为替代方案,我可以这样做

class B: public A {

public:
  B(): A(this->buildCache_())

protected:
  const SomeDataType cache_;

private:
  SomeDataType
  buildCache_()
  {
    // expensive cache construction
    // fill this->cache_ explicitly
    return cache_;
  }

}

这样的缺点是buildCache_()不能const。此外,GCC 抱怨

warning: ‘B::cache_’ should be initialized in the member initialization list [-Weffc++]

是否有更合适的解决方案?

你按原样做的是未定义的行为,来自 [class.base.init]/14,强调我的:

Member functions (including virtual member functions, 10.3) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator (5.2.8) or of a dynamic_cast (5.2.7). However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.

您要做的是使用 Base-from-Member idiom:

class Cache {
protected:
    const SomeDataType cache_;
};

class B : private Cache, public A {
public:
    B() : Cache(), A(cache_)
    { }
};

从 C++11 开始,您可以使用前向构造函数:

class B: public A
{
public:
  B(): B(B::buildCache_()) {}

private:
  B(SomeDataType&& cache) : A(cache), cache_(std::move(cache)) {}

private:
  static SomeDataType buildCache_()
  {
    // expensive cache construction
  }

protected:
    const SomeDataType cache_;
};