Thursday, November 6, 2008
Tuesday, November 4, 2008
The Default Copy Constructor
We’ve seen two ways to initialize objects. A no–argument constructor can initialize data members to constant values, and a multi–argument constructor can initialize data members to values passed as arguments. Let’s mention another way to initialize an object: you can initialize it with another object of the same type. Surprisingly, you don’t need to create a special constructor for this; one is already built into all classes. It’s called the default copy constructor. It’s a one–argument constructor whose argument is an object of the same class as the constructor. The ECOPYCON program shows how this constructor is used.
Objects As Arguments
Now we can see how ENGLCON works. The distances dist1 and dist3 are created using the default constructor (the one that takes no arguments). The distance dist2 is created with the constructor that takes two arguments, and is initialized to the values passed in these arguments. A value is obtained for dist1 by calling the member function getdist(), which obtains values from the user.
Now we want to add dist1 and dist2 to obtain dist3. The function call in main(),
dist3.add_dist(dist1, dist2);
does this. The two distances to be added, dist1 and dist2, are supplied as arguments to add_dist(). The syntax for arguments that are objects is the same as that for arguments that are simple data types like int: The object name is supplied as the argument. Since add_dist() is a member function of the Distance class, it can access the private data in any object of class Distance supplied to it as an argument, using names like dist1.inches and dist2.feet.
Close examination of add_dist() emphasizes some important truths about member functions. A member function is always given access to the object for which it was called: the object connected to it with the dot operator. But it may be able to access other objects. In the following statement in ENGLCON, what objects can add_dist() access?
Monday, November 3, 2008
Overloaded Constructors
It’s convenient to be able to give variables of type Distance a value when they are first created. That is, we would like to use definitions like
Distance width(5, 6.25);
which defines an object, width, and simultaneously initializes it to a value of 5 for feet and 6.25 for inches.
To do this we write a constructor like this:
Distance(int ft, float in) : feet(ft), inches(in)
{ }
This sets the member data feet and inches to whatever values are passed as arguments to the constructor. So far so good.
However, we also want to define variables of type Distance without initializing them, as we did in ENGLOBJ.
Distance dist1, dist2;
In that program there was no constructor, but our definitions worked just fine. How could they work without a constructor? Because an implicit no–argument constructor is built into the program automatically by the compiler, and it’s this constructor that created the objects, even though we didn’t define it in the class. This no–argument constructor is called the default constructor. If it weren’t created automatically by the constructor, you wouldn’t be able to create objects of a class for which no constructor was defined.
Often we want to initialize data members in the default (no–argument) constructor as well. If we let the default constructor do it, we don’t really know what values the data members may be given. If we care what values they may be given, we need to explicitly define the constructor. In ENGLECON we show how this looks:
Distance() : feet(0), inches(0.0) //default constructor
{ } //no function body, doesn’t do anything
The data members are initialized to constant values, in this case the integer value 0 and the float value 0.0, for feet and inches respectively. Now we can use objects initialized with the no–argument constructor and be confident they represent no distance (0 feet plus 0.0 inches) rather than some arbitrary value.
Since there are now two explicit constructors with the same name, Distance(), we say the constructor is overloaded. Which of the two constructors is executed when an object is created depends on how many arguments are used in the definition:
Distance length; // calls first constructor
Distance width(11, 6.0); // calls second constructor
Member Functions Defined Outside the Class
So far we’ve seen member functions that were defined inside the class declaration. This need not always be the case. ENGLCON shows a member function, add_dist(), that is not defined within the Distance class declaration. It is only declared inside the class, with the statement
void add_dist( Distance, Distance );
This tells the compiler that this function is a member of the class but that it will be defined outside the class declaration, someplace else in the listing.
In ENGLCON the add_dist() function is defined following the class declaration. It is adapted from the ENGLSTRC program in Chapter 4:
//add lengths d2 and d3
void Distance::add_dist(Distance d2, Distance d3)
{
inches = d2.inches + d3.inches; //add the inches
feet = 0; //(for possible carry)
if(inches >= 12.0) //if total exceeds 12.0,
{ //then decrease inches
inches –= 12.0; //by 12.0 and
feet++; //increase feet
} //by 1
feet += d2.feet + d3.feet; //add the feet
}
Saturday, November 1, 2008
Destructors
We’ve seen that a special member function—the constructor—is called automatically when an object is first created. You might guess that another function is called automatically when an object is destroyed. This is indeed the case. Such a function is called a destructor. A destructor has the same name as the constructor (which is the same as the class name) but is preceded by a tilde:
class Foo
{
private:
int data;
public:
Foo() : data(0) //constructor (same name as class)
{ }
~Foo() //destructor (same name with tilde)
{ }
};
Like constructors, destructor s do not have a return value. They also take no arguments (the assumption being that there’s only one way to destroy an object).
Thursday, October 30, 2008
Initializer List
One of the most common tasks a constructor carries out is initializing data members. In the Counter class the constructor must initialize the count member to 0. You might think that this would be done in the constructor’s function body, like this:
count()
{ count = 0; }
However, this is not the preferred approach (although it does work). Here’s how you should initialize a data member:
count() : count(0)
{ }
The initialization takes place following the member function declarator but before the function body. It’s preceded by a colon. The value is placed in parentheses following the member data.
If multiple members must be initialized, they’re separated by commas. The result is the initializer list (sometimes called by other names, such as the member–initialization list).
Tuesday, October 28, 2008
Same Name As the Class
There are some unusual aspects of constructor functions. First, it is no accident that they have exactly the same name (Counter in this example) as the class of which they are members. This is one way the compiler knows they are constructors.
Second, no return type is used for constructors. Why not? Since the constructor is called automatically by the system, there’s no program for it to return anything to; a return value wouldn’t make sense. This is the second way the compiler knows they are constructors.
