强制成员变量在基类之前构造

Force member variable to be constructed before base class

本文关键字:基类 成员 变量      更新时间:2023-10-16

我目前面临以下情况:

class foo 
{
public:
    foo ( /* some parameters */ );
};
class bar
{
public:
    bar ( foo & f );
};
// both foo and bar are 3rd party
class base
{
public:
    base ( foo & f ) : m_bar ( f ) {}
private:
    bar m_bar;
};
class derived : public base
{
public:
    derived ( foo & f ) : base ( f ) {}
};
class derived2 : public base
{
public:
    derived2 () : base ( /* well ... */ ) {} 
private:
    foo m_foo;
};

可以看到,foobar被设计成这样使用:

foo f ( /* some parameters */ );
bar b ( f );

然而,如果需要的话,我希望我的包装器类是独立的,derived2需要是。但是,derived2::m_foo不能在未初始化时直接传递给base

所以我的问题是:有没有一种方法可以强制derived2::m_foobase之前构建?

我自己想到的唯一解决办法是:

class derived2_foo
{
protected:
    foo m_foo;
};
class derived2 : public base, public derived2_foo
{
public:
    derived2 () : derived2_foo (), base ( m_foo ) {}
};

这应该是有效的代码(我可以自由地被证明是错误的),但我不太确定如果我想喜欢这个解决方案。所以我在这里寻找其他的想法。

你的基本想法是好的,但是你应该使用私有继承,这样derived2的客户端就不知道里面发生了什么。

class derived2_foo
{
protected:
    foo m_foo;
};
class derived2 : private derived2_foo, public base
{
public:
    derived2 () : derived2_foo(), base ( m_foo ) {}
};

我还改变了基类在类声明中出现的顺序。始终确保类声明中的顺序与初始化列表中的顺序匹配(就像成员变量一样)。正如c++ FAQ所说:

注意顺序B1和B2[…]是由类的声明中基类出现的顺序类中而不是的初始化项出现在派生类中的顺序类的初始化列表

或者更官方的来源,c++标准§12.6.2/13.2:

[…直接基类按声明顺序初始化出现在基本指定符列表中(无论元素的顺序如何) mem-initializers )。

另一个改进是将derived2_foo类放入其自己的"私有"命名空间:

namespace detail
{
    class derived2_foo
    {
    protected:
        foo m_foo;
    };
}
class derived2 : private detail::derived2_foo, public base
{
public:
    derived2 () : derived2_foo(), base ( m_foo ) {}
};
像Boost这样的库也会这样做。虽然detail名称空间在技术上并不隐藏或保护任何内容,但它向客户机发出信号,表明它们不应该依赖于其内容。