I have C++ code that boils down to something like the following:
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); }
Semantically, the bar and baz member variables should be const, since they should not change after initialization. However, it seems that in order to make them so, I would need to initialize them in an initialization list rather than assign them. To be clear, I understand why I need to do this. The problem is, I can't seem to find any way to convert the code into an initialization list without doing one of the following undesirable things:
complex_method
twice (would be bad for performance)Is there any way to make the variables const while avoiding these undesirable situations?
To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.
A constant variable must be initialized at its declaration. To declare a constant variable in C++, the keyword const is written before the variable's data type. Constant variables can be declared for any data types, such as int , double , char , or string .
const objects are objects you dont want to change, they stay constant during the execution of the program. You can assign a value to them in the member initialization list of the constructor of your class but not beyond that. If you have a variable that can have different values, you should not use const.
Yes, you can also initialize these values using the constructor.
If you can afford a C++11 compiler, consider 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)} { }
As a general advice, be careful declaring your data members as const
, because this makes your class impossible to copy-assign and move-assign. If your class is supposed to be used with value semantics, those operations become desirable. If that's not the case, you can disregard this note.
One option is a C++11 delegating constructor, as discussed in other answers. The C++03-compatible method is to use a subobject:
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)) {}
You can make bar
and baz
const, or make the subobject
const, or both.
If you make only subobject
const, then you can calculate complex_method
and assign to bar
and baz
within the constructor of 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); }
The reason that you can't mutate const
members within a constructor body is that a constructor body is treated just like any other member function body, for consistency. Note that you can move code from a constructor into a member function for refactoring, and the factored-out member function doesn't need any special treatment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With