Ways to construct objects
Consider we have a Point
class to represent a
two-dimensional coordinates (x, y)
in Cartesian coordinate system.
Default Constructor
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
class Point
{
public:
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.x << ", " << p.y << ")";
return out;
}
private:
double x;
double y;
};
int main() {
Point p1;
cout << p1 << endl;
return 0;
}
What is the output of the above code? What's the initial value
of x
and y
? The answer is (0, 0)
.
The reason why is that we actually have a default constructor as below:
Point() { // Default constructor
x = 0;
y = 0;
}
That is, our code is same as:
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
class Point
{
public:
Point() { // Default constructor
x = 0;
y = 0;
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.x << ", " << p.y << ")";
return out;
}
private:
double x;
double y;
};
int main() {
Point p1;
cout << p1 << endl;
return 0;
}
Use this
to avoid ambiguous variables
Formally, the default constructor should be defined specifically:
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
class Point
{
public:
Point(double x = 0.0, double y = 0.0) {
this->x = x; // this->x is our inside member, and x is the passed parameter.
this->y = y;
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.x << ", " << p.y << ")";
return out;
}
private:
double x;
double y;
};
int main() {
Point p1;
cout << p1 << endl;
Point p2(2.4, 6.7);
cout << p2 << endl;
return 0;
}
Then we can use arbitrary (x, y)
to initialize the Point
.
The output of above code is:
(0, 0)
(2.4, 6.7)
The this
in constructor is used to disambiguate.
The members x, y
and parameters x, y
should be
clearly differentiated.
Use Prefix to avoid ambiguous variables
Another way to differentiate the member variables and parameters is to use Prefix:
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
class Point
{
public:
Point(double aX = 0.0, double aY = 0.0) {
mX = aX;
mY = aY;
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.mX << ", " << p.mY << ")";
return out;
}
private:
double mX;
double mY;
};
int main() {
Point p1;
cout << p1 << endl;
Point p2(2.4, 6.7);
cout << p2 << endl;
return 0;
}
The m
and a
here are represented as member and argument.
Initializer Lists
The best way to initialize the member variables is to use initializer lists. We will explain why in next lesson. Now we only show how to use it.
#include <iostream>
using std::cout;
using std::endl;
using std::ostream; // for << operator overloading
class Point
{
public:
Point(double aX = 0.0, double aY = 0.0)
: mX(aX)
, mY(aY) // Initialize mX and mY by initializer lists
{
}
// Overwrite the output stream
friend ostream& operator<<(ostream& out, const Point& p)
{
out << "(" << p.mX << ", " << p.mY << ")";
return out;
}
private:
double mX;
double mY;
};
int main() {
Point p1;
cout << p1 << endl;
Point p2(2.4, 6.7);
cout << p2 << endl;
return 0;
}