Initializer list
In previous section, we already know many ways to construct variables. Among these constructors, using initializer list normally is the best ways to construct variables. In this section, we will show you why.
Consider the following case:
We have a Line
class who has two private members
, mStart
and mEnd
.
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
#define DEBUG true
void log(std::string s) {
DEBUG && (cout << "[" << __FILE__ << "]" << s << "\n");
}
class Point
{
friend class Line;
public:
Point()
{
log("Construct Point");
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.mX << ", " << p.mY << ")";
return out;
}
private:
double mX;
double mY;
};
class Line
{
public:
Line(double aAx ,double aAy, double aBx, double aBy)
{
log("Construct Line");
mStart.mX = aAx;
log("Set start point\'s x");
mStart.mY = aAy;
log("Set start point\'s y");
mEnd.mX = aBx;
log("Set end point\'s x");
mEnd.mY = aBy;
log("Set end point\'s y");
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Line& l)
{
out << "from " << l.mStart << " to " << l.mEnd;
return out;
}
private:
Point mStart;
Point mEnd;
};
int main() {
Line l(1, 2, 3, 4);
cout << l << endl;
return 0;
}
The output of above is:
[constructor.cpp]Construct Point
[constructor.cpp]Construct Point
[constructor.cpp]Construct Line
[constructor.cpp]Set start point's x
[constructor.cpp]Set start point's y
[constructor.cpp]Set end point's x
[constructor.cpp]Set end point's y
from (1, 2) to (3, 4)
We can see that we will construct the mStart
and mEnd
first
because they are members.
Then, we will need to assign their mX
and mY
each
in Line
's constructor.
It's not a good idea if one class has many Point
members.
It will cost to many instructions to assign the mX
and mY
.
Instead of assigning after constructing, we can use initializer list
to give values for mX
and mY
when constructing Point
members.
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
#define DEBUG true
void log(std::string s) {
DEBUG && (cout << "[" << __FILE__ << "]" << s << "\n");
}
class Point
{
friend class Line;
public:
Point(double aX = 0.0, double aY = 0.0)
: mX(aX)
, mY(aY)
{
log("Construct Point with init list");
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.mX << ", " << p.mY << ")";
return out;
}
private:
double mX;
double mY;
};
class Line
{
public:
Line(double aAx ,double aAy, double aBx, double aBy)
: mStart(aAx, aAy)
, mEnd(aBx, aBy)
{
log("Construct Line with init list");
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Line& l)
{
out << "from " << l.mStart << " to " << l.mEnd;
return out;
}
private:
Point mStart;
Point mEnd;
};
int main() {
Line l(1, 2, 3, 4);
cout << l << endl;
return 0;
}
The output is:
[constructor.cpp]Construct Point with init list
[constructor.cpp]Construct Point with init list
[constructor.cpp]Construct Line with init list
from (1, 2) to (3, 4)
By using initializer list, we can save a lot of instructions
to assign value to Point
's mX, mY
.
The mX, mY
will be initialize to the corresponding values during
constructing the Point
members.
Note that it make no difference in POD class members. It's just a matter of style.