Previous Table of Contents Next


7.3.4. Special Member Functions

So far, we have glossed over an important aspect of classes: What happens when variables of those classes are created and destroyed? For example, if we want to define a Point whose coordinates are 3 and 4, it would be nice to be able to write something more compact than

   Point p;
   p.x(3);
   p.y(4);

Moreover, copying and assigning a class object are potentially fundamental operations on such an object, and we will see how useful it can be for the definition of copying and assignment of objects of a particular class to be something other than simply copying or assigning their members.

To permit this kind of fine-grained control, C++ provides three kinds of special member functions: the constructor, the destructor, and the assignment operator.

7.3.4.1. Constructors

A constructor is a member function that is invoked automatically every time an object of the given class is created. The destructor is invoked automatically whenever an object is destroyed, and the assignment operator is used whenever such an object appears on the left-hand side of an assignment as part of an expression.

If we do not define any constructors at all for a class, the compiler creates one for us with no parameters. That constructor does nothing beyond constructing the members of the class in the ordinary way. In other words, the compiler actually created a constructor for our Point class that is as if we had written

   Point() { }

One implication of this is that if we say

   Point p;

then p.x() has no meaningful value, because we didn’t give an initial value for p.xval.

Suppose, now, that we wanted to augment our Point class so that the coordinates of a Point would be zero by default, and so that we could explicitly specify the starting values if we wished. Then we might change our class as follows:

   class Point {
   public:
       Point(): xval(0), yval(0) { } Point(int x, int y): xval(x), yval(y)
   { }
       // ...
   };

A constructor looks like any other member function, but there are a few differences:

  Its name is always the same as the name of its class; that is how we know it is a constructor.
  It can have constructor initializers that say how to create the members of its class as part of constructing the class object itself.
  It cannot be const, because it is necessary to modify an object in order to construct it.

In this particular example, we have defined two constructors. The first one says that if we construct a Point without saying what its coordinates are, they are set to zero. The second says that we can give the coordinates for a Point explicitly.

This definition would let us write

   Point p(3, 4);

instead of

   Point p;
   p.x(3);
   p.y(4);

Moreover, we can use expressions such as Point(3, 4) to denote otherwise anonymous Point objects that the compiler constructs automatically for the occasion. So, for example,

   double d = distance(Point(), Point(3, 4));

would set d to 5.0, within the precision of floating-point arithmetic.

7.3.4.2. Copy Constructors

Of the overloaded constructors that a class can have, one is special. That constructor is the one whose parameter is a reference to a constant object of the class type itself. So, for class Point, the special constructor is the one that takes a const Point& parameter.

Such a constructor is called a copy constructor; it describes how to copy an object of the given type. Copying an object is, after all, equivalent to constructing a new object of the same type and initializing it from the object that is being copied. So, for example, we would define an appropriate copy constructor for class Point as

   class Point {
   public:
       Point(const Point& p): xval(p.xval), yval(p.yval) { }
       // ...

   };

This copy constructor initializes xval and yval from the corresponding members of the object that is being copied.

Copy constructors control almost every context in which objects are copied. For example, when we write a function that takes a Point argument:

   void draw(Point p) { /* ... */ }

then every time we call draw, the C++ implementation will use the copy constructor of class Point to copy the argument into the local variable p. Similarly, if p is a Point and we write

   Point q = p;

then the implementation will use the copy constructor to construct q. The copy constructor is even used to return an object from a function. In fact, the only context in which a copy of an object can be formed without using the copy constructor is when on object is assigned to another as part of an expression (rather than as part of a declaration). So, for example, although

   Point q = p;

uses the copy constructor to form q, if we subsequently use

   q = p;

then we will be assigning p to q, obliterating the prior value of q. Such assignments do not use the copy constructor; instead, they use the assignment operator.

It is important to realize that a copy constructor must take a reference parameter. Suppose, for example, that we had written

   Point(Point p): xval(p.xval), yval(p.yval) { } // Wrong!

Then when we called this constructor, we would have to copy the argument to initialize p. How would we copy it? By using the copy constructor. But first we would have to copy the argument to initialize the parameter p. Evidently, the result of trying to define a copy constructor this way would be an infinite recursion.

By defining copy constructors to take references, we say that we do not want to copy the argument before copying it. In effect, the parameter p is bound directly to the argument object, which is just what we want if we are going to copy the argument.

The copy constructor we wrote in this example does just what the default definition of copying does: It copies the components of the object. As it happens, the compiler will generate a copy constructor for us if we don’t write one, and the copy constructor it generates copies the components of the object. So we did not need this particular copy constructor at all—but we will see contexts later in which copy constructors are essential.


Previous Table of Contents Next