我有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
(对表现不利)有没有办法在避免这些不良情况的同时使变量成为常量?
答案 0 :(得分:26)
如果您负担得起C ++ 11编译器,请考虑delegating constructors:
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
,因为这会使您的类无法复制 - 分配和移动 - 分配。如果您的类应该与值语义一起使用,那么这些操作将变得可取。如果情况并非如此,您可以忽略此说明。
答案 1 :(得分: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))
{}
您可以设置bar
和baz
const,或设置subobject
const,或两者兼而有之。
如果您只制作subobject
const,那么您可以计算complex_method
并在bar
的构造函数中分配给baz
和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
成员是因为构造函数体被视为与任何其他成员函数体一样,以保持一致性。请注意,您可以将代码从构造函数移动到成员函数中进行重构,并且分解成员函数不需要任何特殊处理。
答案 2 :(得分: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;
};
答案 3 :(得分:2)
如果您不想使用新奇的委托构造函数(我仍然需要处理不了解它们的编译器版本),并且您不想更改布局在你的类中,你可以选择一个解决方案,用一个返回const void *
的静态成员函数用Foo
参数替换构造函数,同时使用一个私有构造函数将complex_method
的输出作为参数(后者很像委托构造函数示例)。然后,静态成员函数执行涉及complex_method
的必要初步计算,并以return Foo(s);
结束。这确实要求类具有可访问的复制构造函数,即使它的调用(在return
语句中)很可能被省略。