代码之家  ›  专栏  ›  技术社区  ›  Nikola Dim

如何维护类成员的顺序并且仍然有一个工作的构造函数

  •  3
  • Nikola Dim  · 技术社区  · 6 年前

    我要有整洁的头文件,其中puiblic成员首先列出,然后是私有成员。

    class A
    {
    public:
        A() : y(0), z(0), x(y + z)
        {}
    
        int x;
    
    private:
        int y;
        int z;
    };
    

    成员是按照声明的顺序初始化的,因此此构造函数有问题,因为当X使用它们时,Y和Z没有初始化。

    这只是一个我可以写x(0)的例子,但是如果这些不是int而是更大的类型,那么它会很麻烦。 为了解决这个问题,我需要首先列出privete成员y和z, 然后是公共成员X。 在初始化初始值设定项列表中的第一个成员时,是否有任何方法可以让我的私人成员留在底部?

    如果没有,请指导我如何订购会员,因为我在网上找不到任何这样的例子。首先列出一些公开的,然后是一些私人的,然后更多的公开的成员对我来说似乎很肮脏,但也许我错了。

    4 回复  |  直到 6 年前
        1
  •  3
  •   Sneftel    6 年前

    作为一种语言,C++并没有很好地将实现细节保持在头文件之外,或者一般与接口分离。你在这里做的任何事都是妥协。

    一种硬线方法是不使用任何公共成员变量,并为此分离和公开纯虚拟接口(在单独的文件中)。此时,实际的类甚至不需要在一个头文件中——只是在一个源文件中,由工厂函数引用——所以剩余的头文件是您想要的干净的。这不是我推荐的方法。

    在任何情况下,C++中都有各种实际的考虑因素,它们限制类成员的顺序。把所有的公众成员都放在班上是一个很好的计划A,但有时它不会奏效,我也不建议你去任何英雄主义者那里去实现它。

        2
  •  4
  •   Goswin von Brederlow    6 年前

    使用委托构造函数,可以将其编写为:

    class A
    {
    public:
        A() : A(0, 0) { }
        {}
    
        int x;
    
    private:
        explicit A(int y_, int z_) : x(y_ + z_), y(y_), z(z_) { }
        int y;
        int z;
    };
    
        3
  •  2
  •   eerorika    6 年前

    有什么方法可以让我的私人成员在初始化他们的时候留在底层吗?

    不。成员是按照声明的顺序初始化的;这是不可能的。

    如果您只希望成员不在类的顶部,那么可以使用一个基:

    struct B {
        int y;
        int z;
    };
    
    
    class A : B
    {
    public:
        A() : B{0, 0}, x(y + z)
        {}
    
        int x;
    };
    

    首先列出一些公开的,然后是一些私人的,然后更多的公开的成员对我来说似乎很肮脏,但也许我错了。

    在你的情况下,这不是必要的,因为你可以先把所有的私人物品放在第一位,然后把所有的公共物品放在第一位。但一般来说,用相同的访问说明符拆分声明是可以的,尽管很少有必要。

        4
  •  0
  •   pyj    6 年前

    问题是x依赖于y和z,但y和z是已知的。 可能的解决方法:

    (1)传入构造的x,而不是由构造函数生成。

    int y = 1;
    int z = 40;
    int x = y + z;
    A(y, z, x);
    

    (2)一个更疯狂的想法,(请不要这样做,它通常表示您如何考虑代码的问题)。创建默认对象,然后使用Placement New。但是,当我看到这样的代码时,它通常使用 init() 功能或其他。对于Ints来说,这是一种超杀伤力,但我假设你有一个更复杂的类型,这就是为什么你要这样做。

    A() : y(0), z(0), x(/*default construct*/)
    {
      new (&x) int(y + z);
    }
    //or
    A() : y(0), z(0), x(/*default construct*/)
    {
      x.init(y, z);
    }
    

    总的来说,我认为你应该重新评估为什么x依赖于y和z,也许你还需要处理一些数据和职责。

    如果x依赖于y和z的状态,那么如果它在类外部使用,您可能希望将其设置为函数,因为作为公共成员变量,其他人可以修改它,并可能从x和y取消同步。您也可能希望将y和z放在x内部。