class Point { int x; int y; public: friend ostream& operator<<(ostream& s, const Point& p); }; ostream& operator<<(ostream& s, const Point& p){ s << p.x << ' ' << p.y;}if we do:
Point a; cout << a << endl;in a run we made we got as output "536912832 1". That is, the compiler uses an implicit contructor to allocated space for the data members of the Point a and did not initialize them. If we want a default value, say, 0 for both x and y, we need to declare a default constructor like:
Point(int n); .... inline Point(int n) : x(n), y(n){}or, better, we can declare a single constructor which combines the functionality of both:
Point(int n = 0); .... inline Point(int n = 0) : x(n), y(n){}
Beware that the default constructor is defined only as long as no constructor is defined. Suppose we have the class:
class Point { int x; int y; public: Point(int n): x(n), y(n){} };Then if I declare a variable p
Point p;I get a compiler error because the default constructor has become undefine because of the Point(int n) constructor.
Here is an example of class with two constructors, where the default constructor is just like the implicit constructor but it is needed since the existence of the "Book(int c, string a);" constructor eliminates the possibility of using the implicit constructor [this is required in C++].
Suppose we have a function:
void moo(Point p);When moo is called as in
Point b; ... moo(b);b is passed by value, i.e. a copy is implicitly made and given as parameter to moo. In this copy each data member is initialized by the corresponding data member of b. If this default behavior (default copy constructor) implictly done by the compiler is not desired, one can explicitly define a copy constructor, a constructor that takes as its only parameters a const reference to the class. In the case of Point, we would have the constructor method declaration:
Point(const Point& );In reality there is no good reason for a user-defined copy constructor for Point as it is currently defined. Let's instead redefine the Point1 class as follows:
class Point1 { int x; int y; char *name; public: Point1(char * ); Point1(const Point1&); friend ostream& operator<<(ostream& s, const Point1& p); }; Point1::Point1(char *nn): x(0), y(0) { // a default constructor name = new char[1+strlen(nn)]; strcpy(name, nn); } Point1::Point1(const Point1& p): x(p.x), y(p.y){ // copy constructor name = new char[1+strlen(p.name)]; strcpy(name, p.name); } ostream& operator<<(ostream& s, const Point1& p){ s << p.name << ' ' << p.x << ' ' << p.y ;}Now the name data member is a c-string. Thus we have to worry about its allocation and copy (and deallocation). Here is another example of a class with a copy constructor. In this example we also see the use of a class destructor, which we discuss next. Continuing with the copy constructor, we find three occasions where it is used:
What happens when an object is deallocated, say, because declared as a local variable of a function and control returns from the function? The default is that the storage allocated for the object on the stack is deallocated. This may be fine in many cases, but it is not fine in the case of Point1 instances. In this case we need to deallocate the space allocated for the name. This is done by adding the method
~Point1(){delete [] name;}to the Point1 class. Now when a Point1 is deallocated also the space associated with name is freed. A similar use of a destructor can be seen in the previously mentioned example.
Finally we need to consider the copy assignment operator. When we have two instances x and y of a class ClassName, what happens when we execute:
x = y;The compiler will decide if to make a bitwise copy from y to x, or a componentwise copy from the data members of y to the data members of x. But either one of these assignment will do a shallow copy of the pointers stored in y to x. For example in the case of Point1, the name field is copied as a pointer, thus the name c-string becomes shared. To avoid this problem, and have a deep copy, we have defined an assignment operator as it is shown here. Briefly, we just add the operator= to the Point1 class:
Point1& Point1::operator=(const Point1& rhs) { if (this != &rhs) { x = rhs.x; y = rhs.y; if (name != 0) { delete [] name; name = new char[1+strlen(rhs.name)]; strcpy(name, rhs.name); } } return *this; }Here are some other examples on classes: