24

我有 C++ 代码,可以归结为以下内容:

class Foo{
    bool bar;
    bool baz;
    Foo(const void*);
};
Foo::Foo(const void* ptr){
    const struct my_struct* s = complex_method(ptr);
    bar = calculate_bar(s);
    baz = calculate_baz(s);
}

从语义上讲,bar 和 baz 成员变量应该是 const,因为它们在初始化后不应该改变。但是,似乎为了使它们如此,我需要在初始化列表中初始化它们而不是分配它们。说清楚,我明白为什么我需要这样做。问题是,如果不做以下不受欢迎的事情之一,我似乎找不到任何方法将代码转换为初始化列表:

  • 调用complex_method两次(对性能不利)
  • 添加指向 Foo 类的指针(会使类大小不必要地变大)

有什么方法可以使变量 const 同时避免这些不良情况?

4

4 回答 4

27

如果您负担得起 C++11 编译器,请考虑委托构造函数

class Foo
{
    // ...
    bool const bar;
    bool const baz;
    Foo(void const*);
    // ...
    Foo(my_struct const* s); // Possibly private
};

Foo::Foo(void const* ptr)
    : Foo{complex_method(ptr)}
{
}

// ...

Foo::Foo(my_struct const* s)
    : bar{calculate_bar(s)}
    , baz{calculate_baz(s)}
{
}

作为一般建议,请小心将您的数据成员声明为const,因为这会使您的类无法复制分配和移动分配。如果您的类应该与值语义一起使用,那么这些操作将变得可取。如果不是这种情况,您可以忽略此注释。

于 2015-01-19T18:02:38.390 回答
12

一种选择是 C++11 委托构造函数,如其他答案中所述。与 C++03 兼容的方法是使用子对象:

class Foo{
    struct subobject {
        const bool bar;
        const bool baz;
        subobject(const struct my_struct* s)
            : bar(calculate_bar(s))
            , baz(calculate_baz(s))
        {}
    } subobject;
    Foo(const void*);
};
Foo::Foo(const void* ptr)
    : subobject(complex_method(ptr))
{}

您可以制作barbazconst,或制作subobjectconst,或两者兼而有之。

如果你只做subobjectconst,那么你可以计算complex_method并赋值给barbaz的构造函数subobject

class Foo{
    const struct subobject {
        bool bar;
        bool baz;
        subobject(const void*);
    } subobject;
    Foo(const void*);
};
Foo::Foo(const void* ptr)
    : subobject(ptr)
{}
Foo::subobject::subobject(const void* ptr){
    const struct my_struct* s = complex_method(ptr);
    bar = calculate_bar(s);
    baz = calculate_baz(s);
}

您不能在构造函数体中改变成员的原因const是构造函数体被视为与任何其他成员函数体一样,以保持一致性。请注意,您可以将代码从构造函数移动到成员函数中进行重构,并且分解出的成员函数不需要任何特殊处理。

于 2015-01-19T18:08:10.610 回答
8

您可以在 C++11 中使用委托构造函数:

class Foo{
public:
    Foo(const void* ptr) : Foo(complex_method(ptr)) {}

private:
     Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {}

private:
    const bool bar;
    const bool baz;
};
于 2015-01-19T18:02:32.227 回答
2

如果您不想使用新奇的委托构造函数(我仍然必须处理不了解它们的编译器版本),并且您不想更改类的布局,您可以选择一个解决方案它用const void *静态成员函数返回的参数替换构造函数Foo,同时具有一个私有构造函数,该构造函数将输出complex_method作为参数(后者很像委托构造函数示例)。然后静态成员函数进行必要的初步计算,包括complex_method,并以 结束return Foo(s);。这确实要求该类具有可访问的复制构造函数,即使它的调用(在return语句中)很可能被省略。

于 2015-01-19T22:25:53.597 回答