Function in constructor initialiser list? - c++

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()) {
}

Related

Will this void function return a value at all? Or do I have to add a "&"?

Suppose I have a previously written class called Box. I have the following constructor and void function:
Box::Box (double height, double width, double length)
{
setHeight(height);
setWidth(width);
setLength(length);
}
void Box::setHeight(double h)
{
height = h;
}
In my main () function, I later declare:
Box box1(2.4, 7.1, 5.0);
Will 2.4 become the height of my box?
How?
The voidBox::setHeight(double h) doesn't have a "return" value because it's a void function? So how will it set height?
Will 2.4 become the height of my box? How?
Yes, 2.4 will become the height stored in the member variable of your Box object.
Box::setHeight is a member function. It gets an implicit reference to the object on which it is called. When invoked from the constructor, member function gets the a reference to the object being constructed. That is why the assignment
height = h;
inside Box::setHeight would modify the height member variable of your Box object.
do I have to add a &?
No. A reference to the object being constructed is passed implicitly; no action is required on your part.
Note 1: In order for your code to compile, Box needs to have a member variable called height. This is different from the height in the constructor, which is a parameter passed to the constructor from the caller.
Note 2: You can assign member variable height in the constructor by referencing it with this keyword:
this->height = height;
You could also use initialization list to initialize height:
Box::Box (double height, double width, double length)
: height(height)
, width(width)
, length(length)
{
// The body can be left empty
}
Assuming Box looks something like this:
class Box {
private:
double height, width, length;
public:
Box(double height, double width, double length);
void setHeight(double h);
void setWidth(double w);
void setLength(double l);
};
Then Box::setHeight is setting the height member of the class. Member functions can access data members of the class as well as any parameters passed in, so the function doesn't need to return anything to assign a value to the member.

Initializing a constant in a class

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

Nested Constructors C++ [duplicate]

This question already has answers here:
Delegate Constructor C++
(4 answers)
Closed 6 years ago.
I am using SFML and have a class like the following:
#include <SFML\Graphics.hpp>
class Overlay
{
public:
Overlay(int width, int height);
Overlay(const sf::Texture*);
Overlay(const sf::Sprite*);
~Overlay();
private:
sf::Texture _texture;
sf::Image _img;
};
Now the following constructor for Overlay(const sf::Sprite*) is working:
Overlay::Overlay(const sf::Sprite* spr) {
int width = spr->getTexture()->getSize().x;
int height = spr->getTexture()->getSize().y;
_texture.create(width, height);
_img.create(width, height, sf::Color::Transparent);
}
However, the following, nested constructors are not:
Overlay::Overlay(int width, int height)
{
_texture.create(width, height);
_img.create(width, height, sf::Color::Transparent);
}
Overlay::Overlay(const sf::Texture* tex) {
sf::Vector2u textureSize = tex->getSize();
Overlay(textureSize.x, textureSize.y);
}
Overlay::Overlay(const sf::Sprite* spr) {
Overlay(spr->getTexture());
}
To me it looks, like the two snippets should be doing the same thing if the following is executed:
sf::Sprite image;
Overlay mOverlay(&image);
Although both of them compile just fine, when the second code snippet (nested constructors) is called, _img ends up having a size of 0 and its m_pixels array is empty.
Delegating Constructors.
It sounds like you are looking for a Delegating Constructor.
To use a delegating constructor, it should appear in another constructor's member initializer list, not the constructor's body.
In your second snippet, you are constructing a temporary Overlay object the stack. When the constructor returns, the temporary is destroyed and has no effect.
Try defining the constructor like so:
Overlay::Overlay(const sf::Sprite& spr)
: Overlay(spr.getTexture())
{
}
A small code review.
Notice how I used a const sf::Sprite& rather than a const sf::Sprite*? Because the case of spr being a nullptr isn't being handled, it makes sense to pass it by reference to ensure it refers to an object. This also clears up any question as to who owns the texture after the constructor is called.
When you do this, you should also consider declaring the constructor with the explicit keyword like so:
class Overlay
{
public:
explicit Overlay(const sf::Texture&);
explicit Overlay(const sf::Sprite&);
};
This prevents Textures and Sprites from accidentally being turned into Overlays when passing them around.

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.