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

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.

Related

Pass function parameter directly to class variable

I have a class lazy_segment_tree. This is the current constructor
template<typename T>
struct lazy_segment_tree{
int n;
int H;
T base;
vector<T> segtree;
vector<T> lazytree;
T (*join)(T,T);
T (*assign)(int,T,T);
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue){
join=merge;
assign=create;
base=defvalue;
n=seq.size();
}
};
Can't I directly make the construction parameters go to the values in the class variable?
I am not 100% sure what do you mean by 'directly'.
But in this case you should use initializer list to initialize the member variables. More on initializer lists here.
Applied to your code, the constructor would now look like this:
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue)
: join(merge)
, assign(create)
, base(defvalue)
, n(seq.size())
{}
In your original code, all the members are first default-constructed during initialization of the class. Then, the body of the constructor is called where you use '=' to copy assign the constructor parameters.
When initializer list is used, the members are directly constructed with specified parameters.
Depending on what T might be, it may or may not make real difference. Nevertheless, initializer lists are the standard way to initialize class members and you should use it if possible.

Why does the constructor in C++ behave differently when we include variable types while declaring it?

So I created a constructor on a class Point.
Class
class Point {
public:
Point(); //declare default constructor
double x;
double y;
};
Constructor
Point::Point() {
x=0.0;
y=0.0;
}
Now, when I print the default values of x and y in main, they show as 0 and 0, which I expect.
However, just for fun, the changed the declaration of the constructor to the following -
New Constructor declaration
Point::Point() {
double x=0.0;
double y=0.0;
}
Now, when I called the same constructor, I got the value of x and y as 2.16703e-314 and 6.95313e-310 respectively. Now, I know the purpose of a constructor. What I wanted to know was what happens when I add the variable type to x and y when I declare a constructor that it starts to behave like that? Hope the question is clear. Happy to clarify if it isn't.
In C++ you are allowed to "shadow" variables. When you "shadow" a variable, you create a new one with the same name as one in an "outer" scope. Now the name refers to the inner variable, and any changes are not reflected in the outer one.
Compilers with decent warning settings will tell you when you do this.
Point::Point() {
double x=0.0;
double y=0.0;
}
here, x and y are shadowing the Point::x and Point::y member variables. So x=0.0 does not change the x in Point.
The first case
Point::Point() {
x=0.0; // refers to class member variable x
y=0.0; // refers to class member variable y
}
The second case
Point::Point() {
double x=0.0; //Creating local variable with same name as class member variable
double y=0.0; //Creating local variable with same name as class member variable
}
The comments explains what is happening in each case.
So, in the second case when you are trying to access class member variable you are getting junk value as you are creating a local variable with the same name as the class member variable (different memory location compared to class member variable).

C++ dynamically define class member as either an object or a reference to another member

Suppose I have a class as follows:
class Solution {
public:
std::vector<double> x;
}
Suppose I have a function as follows:
void function(Solution& sol) {
// do some calculations on the solution vector
}
Under some circumstances, I will want function to perform calculations directly using the vector x. However, under some circumstances I will want to perform calculations using another vector that is produced by a mapping of the vector x.
Give these possible circumstances, it makes sense to introduce an additional member to the class Solution, but in the first circumstance this additional member will simply refer to x, and in the second circumstance this additional member will itself be another std::vector that is determined by a mapping of some form.
So, ideally I could add a ctor to Solution that creates/defines a member named y either as a std::vector or as merely a reference to x. Then, my function could simply operate directly using y.
How might I do this?
You can define your function as:
void function(std::vector<double>& x)
And pass different vectors to it, depending on circumstances
Edit Using references in ctors
class Solution
{
std::vector<double> x;
std::vector<double>& y;
public:
Solution(std::vector<double>& _y) : y(_y) { }
Solution() : y(x) { }
void function() { /* do work on y*/ }
};
This way your function always operates on the same reference, but you can control what data this reference refers to. Note that x and y are now private -- this ensures that these members are only used locally via function() method.

Initializing in constructors, best practice?

I've been programming in C++ a while and I've used both methods:
class Stuff {
public:
Stuff( int nr ) : n( nr ) { }
private:
int n;
}
Or
class Stuff {
public:
Stuff( int nr ) {
n = nr;
}
private:
int n;
}
Note: This is not the same as this, similar but not the same.
What is considered best practice?
Initializer lists are preferred. See FAQ 10.6
One big advantage to using initializers: If an exception is thrown anywhere within the initializer list, the destructors will be called for those members that had already been initialized -- and only for those members.
When you use the contructor body to initialize the object, it's up to you to handle exceptions properly and unwind the object as appropriate. This is usually much harder to get right.
Use the initializer list when possible. For an int, it doesn't matter much either way, but for a more complex member object, you'd end up with the default constructor of the object being called, followed by an assignment to that object, which is likely to end up being slower.
Plus, you have to do it that way anyway for const members or members which don't have a default constructor.
If possible, use the first version.
The first is initializing using intializer lists, and actually calls the constructors of the members.
The second is assignment. If n was of a type with a default constructor, it the would have already been called, and then you'd be assigning to it. If n didn't have a default constructor, you'd be forced to use the first type. Likewise if n was a reference: int &n.
If there are no constructors of you members that directly take one of the parameters to your constructor, it may be worthwhile to add private static functions that can do the conversion for you.
I generally try to do the initializer list when I can. For one thing, this makes it explicit that you are initializing code in the constructor. const memebers have to be initialized this way.
If you just put code in the constructor's body, it is quite possible someone may decide to come along and move a big chunk of it into a non-constructor "setup" routine later.
It can be taken overboard though. I have a coworker who likes to create classes that have 2 pages of initilizer code, no constructor code, and perhaps 2 pages for the entire rest of the class' code. I find that really tough to read.
I want to add that you don't need to declare the initializer list on the Header (.h). It can be done at the implementation of the constructor (which is very common).
So then:
//Stuff.h
class Stuff {
public:
Stuff( int nr );
private:
int n;
}
//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
//initalize complex members
}
is legal and imo concentrates the initialization of fields where it matters. Sometimes we need to initialize complex members in the body, so you have your initializer list and the complex initialization all in the .cpp file.
The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.
Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.
Arrays can be value-initialized in the initialization list, but not in the constructor body:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
For POD types, you can value-initialize them in the initialization list but not inside the brackets:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.

What is the member variables list after the colon in a constructor good for?

I'm reading this C++ open source code and I came to a constructor but I don't get it ( basically because I don't know C++ :P )
I understand C and Java very well.
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
As far I can "deduce" The first line only declares the construtor name, the "::" sounds like "belongs to" to me. And the code between {} is the constructor body it self.
I "think" what's after the paremeters and the first "{" are like methods default parameters or something, but I don't find a reasonable explanation on the web. Most of the C++ constructors that I found in the examples are almost identical to those in Java.
I'm I right in my assumptions? "::" is like belongs to, and the list after params and body are like "default args" or something?
UPDATE:
Thanks for the answers.
May those be called methods? ( I guess no ) and what is the difference of call them within the constructor body
The most common case is this:
class foo{
private:
int x;
int y;
public:
foo(int _x, int _y) : x(_x), y(_y) {}
}
This will set x and y to the values that are given in _x and _y in the constructor parameters. This is often the best way to construct any objects that are declared as data members.
It is also possible that you were looking at constructor chaining:
class foo : public bar{
foo(int x, int y) : bar(x, y) {}
};
In this instance, the class's constructor will call the constructor of its base class and pass the values x and y.
To dissect the function even further:
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
The ::-operator is called the scope resolution operator. It basically just indicates that TransparentObject is a member of TransparentObject. Secondly, you are correct in assuming that the body of the constructor occurs in the curly braces.
UPDATE: Thanks for the answers. May those be called methods? ( I guess no ) and what is the difference of call them within the constructor body
There is much more information on this subject than I could possibly ever give you here. The most common area where you have to use initializer lists is when you're initializing a reference or a const as these variables must be given a value immediately upon creation.
You are pretty close. The first line is the declaration. The label left of the :: is the class name and for it to be a constructor, the function name has to be the same as the class name.
TransparentObject::TransparentObject( int w, int x, int y, int z )
In C++ you can optionally put a colon and some initial values for member variables before the start of the function body. This technique must be used if you are initialzing any const variables or passing parameters to a superclass constructor.
:
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
And then comes the body of the constructor in curly braces.
{
int bla;
int bla;
}
:: Actually means contains (see comments for clarification), however the _someMethods and so forth is what's called an initialisation list. There is plenty of info at the link =]
EDIT: Sorry, my first sentence is incorrect - see the comments.
Yes, :: is the C++ scoping operator which lets you tell the compiler what the function belongs to. Using a : after the constructor declaration starts what is called an initialization list.
The code between the argument list and the {}s specifies the initialization of (some of) the class members.
Initialization as opposed to assignment---they are different things---so these are all calls to constructors.
You're correct. Its a way to set the default values for the class variables. I'm not too familiar with the exact difference between putting them after : and in the function body.
There are usually some good reasons to use an initialization list. For one, you cannot set member variables that are references outside of the initialization list of the constructor. Also if a member variable needs certain arguments to its own constructor, you have to pass them in here. Compare this:
class A
{
public:
A();
private:
B _b;
C& _c;
};
A::A( C& someC )
{
_c = someC; // this is illegal and won't compile. _c has to be initialized before we get inside the braces
_b = B(NULL, 5, "hello"); // this is not illegal, but B might not have a default constructor or could have a very
// expensive construction that shouldn't be done more than once
}
to this version:
A::A( C& someC )
: _b(NULL, 5, "hello") // ok, initializing _b by passing these arguments to its constructor
, _c( someC ) // this reference to some instance of C is correctly initialized now
{}
Without using the initialiser list all class members will simply have their default constructor called so this is the only place that you can control which constructor is called (for non-dynamically allocated members). The same is true for which parent class constructor will be called.
Class members "initialised" within the body of the constructor (i.e. between the {} braces using the = operator) isn't technically initialisation, it's an assignment. For classes with a non-trivial constructor/destructor it can be costly to default construct and then modify through assignment in this way. For reference members you must use the initialiser list since they cannot be changed via the assignment operator.
If the member (or parent class) does not have a default constructor then failing to specify an appropriate constructor in the initialiser list will cause the compiler to generate an error. Otherwise the compiler will insert the default constructor calls itself. For built in types this does nothing so you will have garbage values there.
Note that the order in which you specify the members in the initialiser list does not affect the order in which they are called. It is always the parent class constructor (if any) first, then the class members in the order in which they are defined in the class definition. The order in which you put them in the initialiser list does not matter and can be the source of subtle bugs...
In the contrived example below it looks like the intention is to initialise m_b with value then m_a with m_b, but what actually happens is that m_a is initialised with m_b (which is itself not yet initialised) then m_b gets initialised with value. m_b will just contain garbage!
struct BadInitialiserListExample
{
BadInitialiserListExample(int value) :
m_b(value),
m_a(m_b) // <-- *BUG* this is actually executed first due to ordering below!
{
}
int m_a;
int m_b;
};