Initializing a constant in a class - c++

I created a simple class for calculating the area of a rectangle.
class Rectangle
{
public:
Rectangle();
Rectangle(const double, const double);
class Invalid { };
double print_square();
private:
const double length, width;
inline bool check();
};
For width and length, I used constants, because they will not be modified in my class. In the constructor, I want to initialize them.
Why do I get an error in constructor body?
Cannot assign to non-static data member 'length' with const-qualified
type 'const double'
Constructor for 'Rectangle' must explicitly initialize the const
member 'length'
Error:
Rectangle::Rectangle(const double _length, const double _width)
{
length = _length;
width = _width;
if (!check())
throw Invalid();
}
OK:
Rectangle::Rectangle(const double _length, const double _width) : length(_length), width(_width)
{
if (!check())
throw Invalid();
}
I quite like the second option, but for a more convenient readability I do not want to write all the initialized variables in one line.
Is there a way to initialize a constant in the body of the constructor?

No, you can't.
This is because in your first example, since there is nothing in the initializer list, length and width will be default constructed, and then, in the body of the constructor, assigned the needed values _length and _width, which fails because they are constand already initalized.
In your second example, both variables are initialized without being default constructed. This approach constructs the const variables directly with the needed values, in one step.
Note that approach 2 uses only one step instead of two, so it is more efficient than what you want to do in approach 1. Because of that, it is generally good practice (even for non-const variables) to go with approach 2 whenever possible.

Is there a way to initialize a constant in the body of the constructor?
No.
You must use the initializer list (your second solution):
Rectangle::Rectangle(const double _length, const double _width) :
length(_length),
width(_width)
{
if (!check())
throw Invalid();
}
As already stated in a comment, you can put each variable initialization on a separate line

Related

how do I initialize a const int member in class constructor

I would to initialize a const int member (numGrids) of my class TestCase when I construct a TestCase. It needs to be const (I think) because it defines the elements of another array member of the classwhich I would also like to initialize when I create a TestCase. The code is shown below:
/////////////////////////////////////////////////////////////////////////////////////
//TestCase.h
class TestCase
{
protected:
const int numGrids;
Grid meshes[numGrids];
public:
TestCase(const int);
};
/////////////////////////////////////////////////////////////////////////////////////
//TestCases.cpp
TestCase::TestCase(const int numGridsSpec)
{
numGrids = numGridsSpec;
Grid grids[numGrids];
}
I cannot seem to initialize the const member of my class. I need that member to be constant because it defines the array size of meshes. I get the following errors:
[ 12%] Building CXX object sources/CMakeFiles/GridRefinementStudy.dir/TestCase.cpp.o
In file included from /home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:16:0:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:5:12: error: invalid use of non-static data member ‘TestCase::numGrids’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:6:14: error: from this location
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:6:22: error: array bound is not an integer constant before ‘]’ token
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp: In constructor ‘TestCase::TestCase(int)’:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:25:1: error: uninitialized member ‘TestCase::numGrids’ with ‘const’ type ‘const int’ [-fpermissive]
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:28:13: error: assignment of read-only member ‘TestCase::numGrids’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:29:21: error: no matching function for call to ‘Grid::Grid()’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:29:21: note: candidates are:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:13:2: note: Grid::Grid(int, int, double, double)
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:13:2: note: candidate expects 4 arguments, 0 provided
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:1:7: note: Grid::Grid(const Grid&)
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:1:7: note: candidate expects 1 argument, 0 provided
make[2]: *** [sources/CMakeFiles/GridRefinementStudy.dir/TestCase.cpp.o] Error 1
make[1]: *** [sources/CMakeFiles/GridRefinementStudy.dir/all] Error 2
make: *** [all] Error 2
You may not do such a way. The size of the array shall be known at compile time. In fact you are trying to get a variable length array. C++ does not have such a feature.
Take into account that if the sizes of the array are different for two objects then the classes that define them are different types. They have different data members that is arrays with different sizes. The size of a class shall be the same for each object of that class.
I would suggest to use standard container std::dynarray if the compiler supports it or
std::vector
On the other hand you could define your class as a template class. For example
template <size_t numGrids>
class TestCase {
protected:
Grid meshes[numGrids];
//...
or even as
template <size_t numGrids>
class TestCase {
protected:
std::array<Grid, numGrids> meshes;
//...
I think that using a template class is the best approach in your case.
In pre-C++11, there are four ways of initializing a member:
If the member is static, const and has an integral type,
it can be initialized directly in the class definition. In this
case, the member is a "integral constant expression", and can be
used anywhere the compiler requires such (e.g. array dimensions,
template argument, etc.).
If the member is static, it must be initialized in its
definition. If the member is also const, it is a constant
expression in the translation unit which contains the
definition, after the definition.
Any member can be initialized in the initializer list, and
typically, all should be (but there are exceptions). Non-static
const members must be initialized here (but non-static const
members are not constant expressions, and cannot be used as
such).
Finally, non-const members can be "initialized" in the
constructor body. Formally, this is assignment, not initialization, and if
the member type has a user defined constructor, it will still be
initialized (using the default constructor) in the
initialization list. For primitive types, the member remains
uninitialized if it isn't mentionned in the initializer list,
until it is first assigned.
In your case, it would appear that you want an array whose size
is defined by a parameter to the constructor. This is not
possible; the size of an array must be an integral constant
expression. If the size should always be the same, then you can
use a static const int to define it:
class TestClass
{
static int const numGrids = 25;
Grid meshes[numGrids];
// ...
};
Otherwise, you'll have to use:
class TestClass
{
std::vector<Grid> meshes;
public:
TestClass( int size ) : meshes( size ) {}
};
This might be the better solution anyway.
First of all since numGrids is const in the class declaration, you can only initialize it through initialization list.
TestCase::TestCase(const int numGridsSpec)
:numGrids(numGridsSpec) // this is the initialization list
{
...
}
This is simply because a constant variable can only be set to a value once and can not be modified 'legally' thereafter, compilers normally would not allow you to proceed avoiding unexpected consequences in this case.
There's a mistake in your code. The array size is dynamic (a variable). You can't use a variable to declare an array size at compile time. Use some constants with real value.
To Answer your question
Initializer list is used to init the data for a const. Something as follows.
class TestCase {
protected:
const int numGrids;
public:
TestCase(const int x) : numGrids(x)
{
}
};
Solution for your problem
class TestCase {
protected:
const int numGrids;
Grid* pMeshes;
public:
TestCase(const int x) : numGrids(x)
{
pMeshes = new Grid[x];
}
~TestCase() : numGrids(x)
{
delete []pMeshes; // release allocated memory in destructor
}
};
int main(int argc, char* argv[])
{
TestCase t(10);
return 0;
}
If your compiler supports c++11, you could simply do:
class TestCase
{
protected:
const int numGrids = 25;
Grid meshes[numGrids];
public:
TestCase(const int);
};

Function in constructor initialiser list?

Heyy, I am trying to switch from initialising my variables within the constructor to using the constructor initialiser list.
So instead of writing
Class::Class(int width, int height) {
this->width = width;
this->height = height;
}
I am doing this:
Class::Class(int width, int height) :
width(width),
height(height) {
}
That's all working, but now my problem... Say I have the following constructor:
Class::Class(int width, int height) {
this->width = width;
this->height = height;
this->state.setCurrState(this->state.stateMenu);
this->state.setPrevState(this->state.getCurrState());
}
"state" is just an object of the class "State" which I create in my header. The functions setCurrState and setPrevState are of the type void and just set the class's private variable.
How do I convert the constructor? I know it is possible to write functions in the initialiser list, but the functions I want to add do not return anything... they are void, so I do not know how I would call them?
Class::Class(int width, int height) :
width(width),
height(height)
// call functions here... but how?
{
}
Thank you so much I hope you can help me <3
There is no additional point and advantage to call those functions in initializer list, at least in your case.
Simply call them in the constructor body.
Important note:
You said state is a member of Class. So in constructor's level, state is not constructed yet, then constructing it by itself is somehow meaningless:
state.setCurrState(state.stateMenu);
state.setPrevState(state.getCurrState());
Try to write a well constructor for state's class to set curr/prev to a initial states.
Easy solution: Leave the initializing functions in the body of the constructor.
Slightly more difficult solution:
Add a constructor to State to initialize it from an argument.
Write new functions that return the value that you want to pass to the constructor of State.
setCurrState and setPrevState are not formally initializing your state object, they are merely changing it's "state" (no pun intended) after it has been initialized.
If you consider them to be semantically initializing you state object, then you might as well formalize that by incorporating them in state's constructor (which should receive the needed states and set them right away). You can then initialize it in the initializer list.
Add a function that returns a State:
State GiveMeAState() {
State state;
state.setCurrState(state.stateMenu);
state.setPrevState(state.getCurrState());
}
and use it in your initialization list:
Class::Class(int width, int height) :
width(width),
height(height),
state(GiveMeAState()) {
}

Assign to constant variable in a constructor?

In C++ how do I make a variable constant but assign to it in a constructor? The reason I want to do this is because I'm trying to use data driven design by putting all my data into an XML file and then loading that data into variables. The problem is that I can't load the values in a initialization list so I have to do it in the constructor (or elsewhere), but then the variables aren't constant.
Here's an XML file:
<weapons>
<pistol>
<damage>5.0</damage>
...
</pistol>
...
</weapons>
Then I've got a class like:
header
class Weapon
{
public:
Weapon();
const float damage;
};
source
#include "Weapon.h"
Weapon::Weapon()
{
//load damage value into damage variable
}
Because the damage variable is constant I can't do anything with it in the constructor, only in the initializer list, but obviously I can't execute code like reading an XML file in the initializer list. So even though the variable will never change should I just not make it constant or is there a proper way to leave it constant and do what I need?
Use an initializer-list:
#include "Weapon.h"
Weapon::Weapon() : damage(3.4)
{
}
You could have a xml parser, for example:
class WeaponXMLParser
{
public:
WeaponXMLParser(const std::string& filename);
float getDamage();
};
Initialize const member in initializers list:
Weapon::Weapon(const WeaponXMLParser& wxp) : damage(wxp.getDamage())
{
}
The body of the constructor indeed runs too late, your const members already have a value. that comes from the initializer list :
Weapon::Weapon()
: damage(0.0f) // 0.0f is the default value
{
}
In your case, you'd have to get it from the XML file, e.g.
float Weapon::LoadDmgFromXML();
Weapon::Weapon()
: damage(LoadDmgFromXML())
{
}
One approach is to use a "builder" class. So in your case you might have WeaponBuilder with appropriate methods that lets you do this:
WeaponBuilder wb(xmlFilename);
Weapon w(wb);
Then everything will be available in Weapon's constructor, so that you can make appropriate things const.
you must do it in initializer list. And you can provide a function that will determine what damage is and returns it, so you can set your const variable:
class Weapon
{
public:
Weapon():damage(damage_xml()){}
const float damage;
private:
float damage_xml();
};
You could use const_cast and make a non-const reference to the const variable.
float &_damage = const_cast<float&>(damage);
_damage = 12.34;

C++ OOP which way is better to give values to constructor

I am currently learning C++ and having some problems understanding on how to give values to the constructor. Got my exercise working but am not sure which way is smartest/best.
Way nr. 1
class Vector2d{
public:
Vector2d(double x, double y):x(x),
y(y)
{
}
and way nr.2
class Vector2d{
public:
void set_values (double,double);
Vector2d()
{
}
void Vector2d::set_values (double a, double b) {
x = a;
y = b;
}
Found both ways by reading some tutorials and both ways are working. I guess the first one is more efficient as I don´t have to write a new void, but I am not exactly sure what
:x(x),
y(y)
is doing/meaning.
Thanks a lot in advance!
In C++ doing it by saying
:x(x),
y(y)
You will actually save instructions when it is compiled. The compiler will actually initialize those variables directly inline when space is made for the class.
So I would say that way is better.
I am not exactly sure what [code...] is doing/meaning.
They are initializing your member variables.
It's probably confusing because your constructor parameters were given the same names. Consider this equivalent:
Vector2d(double x_param, double y_param)
: x(x_param) // initialize member variable "x"
, y(y_param) // initialize member variable "y"
{
}
It's reasonable for your class to have both this constructor, and the set_values function to change the values after construction.
Constructor with parameter is created to initialize the member attributes of the class (your 1st solution) and it is different from default constructor (with no parameters - constructor in your 2nd solution).
In your second solution, you are using a setter (a member function to set the values of member attributes) which we can call anytime we need to set the values but with the constructor with parameters (1st solution), we can only set the values for the first time when we create an object to that class.
For example;
when we create the object;
Vector2d vec2d(2.3, 4.5);
it will set the values of x and y to 2.3 and 4.5 respectively but what will we do if we need to set the values again in the program? We will then use setter function like;
vec2d.set_values(5.0, 7.8);
so in short, we only use what we need according to our scenario. If we don't want to set the values again then constructor with parameters (your 1st solution) is the best.
We do the following
:x(x),
y(y)
to assign the value of x and y coming through parameters in constructor to the class members x and y. It is the same as;
class Vector2d{
public:
Vector2d(double x, double y)
{
//"this" pointer is used to differentiate the variables
this->x = x;
this->y = y;
}
}
or for the simplicity I would suggest to use different names if you don't know about this pointer yet;
class Vector2d{
public:
Vector2d(double a, double b)
{
x = a;
y = b;
}
}
with #1 you are instructing the program to initialize x,y by calling their constructor
with #2 you are calling operator= to overwrite the value of x,y by: the value obatained by calling the two constructors: x.operator=(double(right_value))
doesn't differ much since the type involved is "double", would be much different with some complex classes i guess
First way is calling the constructor to initialize members; second way is calling member function to change the value of member variables by assigning, since you only define default constructor, initially members are initialized with default value, then if you call the set_values function, they are reassigned inside that function body. In the current example, they will have the same effect. But it is usually better to initialize member variables at the constructor's initializer list. Your second way looks like a setter function. You cannot use the second way to initialize class member variables since it is not static.
It is preferrable to use the first way if you are constructing an object.
Using the initializer list, the members are created and initialized only once, with the given value.
If you will use separate function to initialize your object, than between constructor call and initialization, your object will be in unitialized state.
The only case you need it - when really know what are you doing.
And also initializing in constructor is faster. When you write
my_class()
: field_(value)
{
}
your field initialized by copying value into it. In other case it initialized, when copied, which is overhead.

Should I declare this as const int member variables of the class?

I have some values such as width, height among some other that I set in the constructor at this moment. They are not currently constants but I want them to be that so I will change them now.
But I heard that it is not common to make such variables private const without also doing private static const. Is this the case? Or is it valid in this case? I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I make them constants?
Are these values specific to the instance of the object, but only set in the constructor? Then static does not make sense, as every object would have the same height and width.
If you make a private data member const, the default assignment operator won't work and you will need to provide one.
But I heard that it is not common to make such variables private const without also doing private static const.
That's a useless generalisation.
Will the values differ between instances?
Yes: make them instance members;
No: make them static members.
That's all there is to it!
I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I make them constants?
Yes, but consider doing this with an accessor function instead.
double T::centerWidth() {
return this->width / 2;
}
I have some values such as width, height among some other that I set in the constructor at this >moment. They are not currently constants but I want them to be that so I will change them now.
But I heard that it is not common to make such variables private const without also doing private >static const. Is this the case?
So, the way I would do this usually if you actually want them to be constant is as follows:
// Header
class Widget
{
public:
Widget();
~Widget();
// rest of your functions/variables
private:
static const int width;
static const int height;
// rest of your functions/variables
}
// Implementation
const int Widget::width = 640;
const int Widget::height = 800;
Widget::Widget()
{
// do some construction work
}
// ... rest of your definitions
Or is it valid in this case?
It's valid if the members you declare static will be the same for each object instance of the class you create.
I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I >make them constants?
Yes, you can use a variable declared const in operations as normal:
const int a = 2;
int b = 2;
int c = a + b; // 4
If you are not going to change these variables by member functions then you do should declare them const and initialize in constructor initialization list.
class A
{
public:
A(int w) : width(w)
{
}
private:
const int width;
};
int main()
{
A(10);
return 0;
}
Since you set your variables in the constructor, they are instance specific, so static does not make any sense.
I know what problem you are trying to solve. You are trying to provide users read-only access to the width and height of an image, while allowing modifications from the class. You can not do that by declaring member variables const. All modification, including copy construction and assignment needs them to be non-const.
One solution is to use a public getter and a protected/private setter. In my own class I use the public member functions called xs() and ys() to return xsize and ysize respectively.
DO NOT EVEN THINK about declaring variables public const and using const_cast tricks to copy and assign, unless you like subtle, deep, pervasive bugs arising from improper compiler optimization and undefined behavior of const_cast.