This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 5 years ago.
I saw this piece of code
class Foo {
public:
int x;
double y;
float z;
Foo(int x, double y, float z)
// XXX: What are the following doing?
: x(x),
y(y),
z(z) {}
}
I'm guessing what was written after the : is assigning the values to the members (x, y, z ) from the arguments.
Question 1: Why that way and not the following?
Foo(int x, double y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
Question 2: in the original style, how does the compiler distinguish the member x from the parameter x? (In my modified pice of code, the qualifier this was used for that purpose)
For example, if I were to write this:
Foo(int x, double y, float z)
// XXX: What are the following doing?
: x(x * 2),
y(x * 3 + y ), // which 'x' is the 'x' in 'x * 2'?
z(z) {}
}
You guess correctly. Those are member initializer lists. The reason this is preferred over directly assigning in the constructor is because it is necessary for const class members, classes with no default constructors, and reference variables. Example:
class A
{
int b;
public:
A(int c) : b(c) {}; // No default constructor
};
class Test
{
A a; // A class with no default constructor
const int x; // A constant
int& r; // A reference
public:
Test(int d) : a(5), x(2), r(d) {};
};
int main()
{
Test test;
}
In this example, both members a and x of class Test cannot be assigned to because the first has no default constructor, while the latter is constant, meaning assignment to it would create an error. Finally, since reference variables cannot be assigned to, an initializer list is needed.
In the end, the primary difference comes down to the fact that initializer lists initialize the variable (who knew?), while assignment in the constructor is done after those member variables' constructors have been called.
As for your second question, you can see for yourself that the parameters are picked before the member variables during the initialization.
Related
This question already has answers here:
How to initialize const member variable in a class?
(11 answers)
Closed 1 year ago.
I'm trying to create a structure (or class, doesn't matter) whose constructor assigns values to the struct's constant parameters. I.e I don't want to change any variables of a Point object after its creation.
Following code obviously doesn't work, because the constructor tries to change the value of a constant.
struct point
{
const int x;
const int y;
point(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
};
point myPoint = point(5, 10);
std::cout << myPoint.x << myPoint.y << std::endl;
Use member initializer list:
struct point
{
const int x;
const int y;
point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
};
I am currently trying to create a constructor that takes in two variables, yet the program has to be able to create an object with only one variable. If the object being constructed is missing the second variable it must initialize it to zero.
constructor(int x, int y)
Example:
constructor a (5, 5)
constructor b(0)
You can have multiple constructors for one class that have different signatures:
class Foo {
public:
int x, y;
Foo() : x(0), y(0) {}
Foo(int _x) : x(_x), y(0) {}
Foo(int _x, int _y) : x(_x), y(_y) {}
}
Foo a(5); // a.x == 5, a.y == 0
Foo b(5, 5); // b.x == 5, b.y == 5
Just like regular functions, the parameters of a constructor can have a default value. Using
constructor(int x, int y = 0) : x_var(x), y_var(y) {}
Allows you to call the constrcutor with either one or two parameters. You can even use
constructor(int x = 0, int y = 0) : x_var(x), y_var(y) {}
which now lets you call the constructor with zero, one, or two parameters.
This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 4 years ago.
class Sales_data {
public:
Sales_data(int i, int j, int k) : x(i), y(j), z(k) {
}
private:
int x,y,z;
};
In the above code(more specifically in Sales_data constructor(recited below)), I don't understand the use of colon and comma separated list.
Sales_data(int i, int j, int k) : x(i), y(j), z(k) {
}
I have never seen a colon(":") following any function/constructor parameter list. What does this colon mean/signify here ?
Moreover, what is this comma separated list after colon ?
You may be confused, because the member variable name (x) is same as the function parameter (also x), which you can always avoid for clarity. Simplified code can look like so.
add_x(int x1) : x(x1) // a contructor that initializes the member vaiable x to x1
{
}
Still confused? then you can go for this ( not so optimize though)
add_x(int x1)
{
x = x1;
}
This is a constructor
This is not a standard function/method. Each class (struct) can have constructor(s). The constructor has the same name as the class and can optionally take parameters.
struct add_x {
int x;
add_x(int x) : x(x) {} // This is a constructor with one paramter
};
To make it easier to read let us format it better.
struct add_x {
int x;
add_x(int x) // Constructor that takes one argument.
: x(x) // This is called the initializer list.
{} // This is the body of the constructor.
};
The initializer list allows you to list out the member variables (comma separated) and initialize them before the body of the constructor is executed.
In this case the member x is initialized with the parameter x.
#include <iostream>
int main()
{
add_x test(5);
std::cout << test.x << "\n"; // Should print 5
// Note in my example I have removed the private
// section so I can read the value x.
}
I recall I used to be able to do this and have it work as intended:
class foobar
{
public:
foobar(int x, int y)
{
x = x; //the variables x, y belonging to the class got correctly initialized
y = y;
}
private:
int x, y;
};
The above worked in circa 200x on Microsoft Visual C++ 6.0 and some later versions, I believe.
But now I have to do this on Microsoft Studio 2013 and I have to use this->, as such:
class foobar
{
public:
foobar(int x, int y)
{
this->x = x; //the other way no longer initializes class vars
this->y = y;
}
private:
int x, y;
};
Was there a language spec change or Microsoft compiler change?
Perhaps you are thinking instead of initializer list syntax, which would be unambiguous and should work correctly on any (non-buggy) C++ compiler:
foobar(int x, int y) : x(x), y(y) { }
In this case, the x and y before the parens are unambiguously data members, because that's the only thing that can go there (besides constructors for parent types). Inside the parens, the x and y refer to the constructor arguments that shadow the data members.
I can't think of any circumstance under which x = x; would do anything other than no-op self-assignment (buggy user-defined assignment operator overloads aside). If this worked in a prior VC++ version then it would have been a VC++ compiler bug. More likely, you used to use initializer list syntax (which does work) and forgot that's what you did.
Or this.
class foobar {
public:
foobar(int x, int y) : x(x), y(y)
{
}
private:
int x, y;
};
What is the difference between this two constructor?
int x, y; //position
BasePoint(int px, int py) : x(px), y(py) {}
and
int x, y; //position
BasePoint(int px, int py)
{
x = px;
y = py;
}
What is x(px), y(py) called? And When do I use this type of variable initialization?
Thanks.
First one is doing initialization using initialization-list, and second one is doing assignment using assignment operator.
First one is recommended!
BasePoint(int px, int py) : x(px), y(py) {}
^^^^^^^^^^^^^ this is called initialization-list!
Read this FAQ : Should my constructors use "initialization lists" or "assignment"?
The FAQ answer starts with :
Initialization lists. In fact,
constructors should initialize as a
rule all member objects in the
initialization list. One exception is
discussed further down [...]
Read the complete answer.
What is x(px), y(py) called?
These are called initializer lists. What you are actually doing is copying the value of px to x and py to y.
Uses:
class foo
{
private:
int numOne ;
public:
foo(int x):numOne(x){}
};
class bar : public foo
{
private:
int numTwo;
public:
bar(int numTwo): foo( numTwo ), // 1
numTwo(numTwo) // 2
{}
};
bar obj(10);
1. Notice that derived constructor's argument can be passed to base class constructor.
2. Compiler can resolve, in this case, which one is argument and which one is member variable. Had if, this needs to be done in the constructor,then -
bar::bar(int numTwo) : foo( numTwo)
{
this->numTwo = numTwo; // `this` needs to be used. And the operation is called assignment. There is difference between initialization and assignment.
}
BasePoint(int px, int py) : x(px), y(py) {}
here u are using the initialization list
so the object when constructed will not go inside the body and initiate those values.it saves time by not entering in the body of the constructor
Another use of this is when calling the derived class constructor.
where if you use the statement like
new derivedclass(a,b,c)
and you can write this
derivedclass(int x,int y,int z):baseclass(a,b),h(z){}