The definition of the overloaded assignment operator would then go on to set the new member variables that were introduced in the definition of the class Derived.. If Derived is a class
Trang 1When overloading the assignment operator in a derived class, you normally use the overloaded assignment operator from the base class To help understand the code out-line we will give, remember that an overloaded assignment operator must be defined as
a member function of the class
If Derived is a class derived from Base, then the definition of the overloaded assignment operator for the class Derived would typically begin with something like the following:
Derived& Derived::operator =(const Derived& rightSide)
{
Base::operator =(rightSide);
The first line of code in the body of the definition is a call to the assignment operator of the Base class This takes care of the inherited member variables and their data The definition of the overloaded assignment operator would then go on to set the new member variables that were introduced in the definition of the class Derived A com-plete example that includes this technique is given in the programming example “Par-tially Filled Array with Backup” later in this chapter.
A similar situation holds for defining the copy constructor in a derived class If Derived is a class derived from Base, then the definition of the copy constructor for the class Derived would typically use the copy constructor for the class Base to set the inherited member variables and their data The code would typically begin with some-thing like the following:
Derived::Derived(const Derived& Object)
: Base(Object), <probably more initializations>
{
The invocation of the base class copy constructor Base(Object) sets the inherited member variables of the Derived class object being created Note that since Object is of type Derived, it is also of type Base; therefore, Object is a legal argument to the copy constructor for the class Base A complete example that includes a copy constructor in
a base class is given in the programming example “Partially Filled Array with Backup” later in this chapter.
Of course, these techniques do not work unless you have a correctly functioning assignment operator and a correctly functioning copy constructor for the base class This means that the base class definition must include a copy constructor and that either the default automatically created assignment operator works correctly for the base class or the base class has an overloaded definition of the assignment operator
If a base class has a correctly functioning destructor, it is relatively easy to define a cor-rectly functioning destructor in a class derived from the base class When the destructor for the derived class is invoked, it automatically invokes the destructor of the base class,
Trang 2so there is no need for the explicit writing of a call to the base class destructor; it always happens automatically The derived class destructor thus need only worry about using delete on the member variables (and any data they point to) that are added in the derived class It is the job of the base class destructor to invoke delete on the inherited member variables
If class B is derived from class A and class C is derived from class B, then when an object of class C goes out of scope, first the destructor for the class C is called, then the destructor for class B is called, and finally the destructor for class A is called Note that the order of destructor calls is the reverse of the order in which constructors are called.
We give an example of writing a destructor in a derived class in the programming example “Partially Filled Array with Backup.”
PARTIALLY FILLED ARRAY WITH BACKUP
This example presents a derived class of the partially filled array class PFArrayD that we pre-sented in Chapter 10 (Display 10.10) For reference we repeat the header file for the base class
PFArrayD in Display 14.8 We repeat as much as we will discuss of the implementation for the base class PFArrayD in Display 14.9 Note that we have made one important change to the defini-tion presented in Chapter 10 We have changed the member variables from private to protected This will allow member functions in the derived class to access the member variables by name
We will define a derived class called PFArrayDBak using PFArrayD as a base class An object of the derived class PFArrayDBak will have all the member functions of the base class PFArrayD
and can be used just like an object of the class PFArrayD, but an object of the class PFArrayD-Bak will have the following added feature: There is a member function called backup that can make a backup copy of all the data in the partially filled array, and at any later time the pro-grammer can use the member function restore to restore the partially filled array to the state it was in just before the last invocation of backup If the meaning of these added member functions
is not clear, you should peek ahead to the sample demonstration program shown in Display 14.12 The interface for the derived class PFArrayDBak is shown in Display 14.10 The class PFArrayD-Bak adds two member variables to hold a backed-up copy of the partially filled array: a member variable b of type double* that will point to a dynamic array with the backup version of the (inherited) working array, and an int member variable named usedB to indicate how much of the backed-up array b is filled with data Since there is no way to change the capacity of a
PFArrayD (or a PFArrayDBak), there is no need to back up the capacity value All the basic functions for handling a partially filled array are inherited unchanged from the base class
PFArrayD These inherited functions manipulate the inherited array a and the inherited int
variable used just as they did in the base class PFArrayD The implementation of the new member functions for the class PFArrayDBak is shown in Display 14.11 The constructors of the derived class PFArrayDBak rely on the constructors of the base class
to set up the regular partially filled array (inherited member variables a, used, and capacity)
Trang 3Display 14.8 Interface for the Base Class PFArrayD
1 //This is the header file pfarrayd.h This is the interface for the class
2 //PFArrayD Objects of this type are partially filled arrays of doubles
3 #ifndef PFARRAYD_H
4 #define PFARRAYD_H
5 class PFArrayD
6 {
7 public:
8 PFArrayD( );
9 //Initializes with a capacity of 50
10 PFArrayD(int capacityValue);
11 PFArrayD(const PFArrayD& pfaObject);
12 void addElement(double element);
13 //Precondition: The array is not full
14 //Postcondition: The element has been added
15 bool full( ) const;
16 //Returns true if the array is full, false otherwise
17 int getCapacity( ) const;
18 int getNumberUsed( ) const;
19 void emptyArray( );
20 //Resets the number used to zero, effectively emptying the array
21 double& operator[](int index);
22 //Read and change access to elements 0 through numberUsed - 1
23 PFArrayD& operator =(const PFArrayD& rightSide);
24 ~PFArrayD( );
25 protected:
26 double *a; //for an array of doubles
27 int capacity; //for the size of the array
28 int used; //for the number of array positions currently in use
29 };
30 #endif //PFARRAYD_H
This class is the same as the one in Display 10.10, except that we have made the member variables protected instead of private
It would be good to place this class in a namespace, but we have not done so in order to keep the example simple
Trang 4Display 14.9 Implementation for the Base Class PFArrayD (part 1 of 2)
1 #include <iostream>
2 using std::cout;
3 #include "pfarrayd.h"
4 PFArrayD::PFArrayD( ) : capacity(50), used(0)
5 {
6 a = new double[capacity];
7 }
8 PFArrayD::PFArrayD(int size) : capacity(size), used(0)
9 {
10 a = new double[capacity];
11 }
12 PFArrayD::PFArrayD(const PFArrayD& pfaObject)
13 :capacity(pfaObject.getCapacity( )), used(pfaObject.getNumberUsed( ))
14 {
15 a = new double[capacity];
16 for (int i =0; i < used; i++)
17 a[i] = pfaObject.a[i];
18 }
19 double& PFArrayD::operator[](int index)
20 {
21 if (index >= used)
23 cout << "Illegal index in PFArrayD.\n";
24 exit(0);
26 return a[index];
27 }
28
29 PFArrayD& PFArrayD::operator =(const PFArrayD& rightSide)
30 {
31 if (capacity != rightSide.capacity)
33 delete [] a;
34 a = new double[rightSide.capacity];
36 capacity = rightSide.capacity;
37 used = rightSide.used;
This is part of the implementation file pfarrayd.cpp The complete implementation is given in Display 10.11, but what is shown here is all you should need for this chapter
Trang 5Display 14.9 Implementation for the Base Class PFArrayD (part 2 of 2)
40 return *this;
41 }
42 PFArrayD::~PFArrayD( )
43 {
44 delete [] a;
45 }
Display 14.10 Interface for the Derived Class PFArrayDBak
1 //This is the header file pfarraydbak.h This is the interface for the class
2 //PFArrayDBak Objects of this type are partially filled arrays of doubles
3 //This version allows the programmer to make a backup copy and restore
4 //to the last saved copy of the partially filled array
5 #ifndef PFARRAYDBAK_H
6 #define PFARRAYDBAK_H
7 #include "pfarrayd.h"
8 class PFArrayDBak : public PFArrayD
9 {
10 public:
11 PFArrayDBak( );
12 //Initializes with a capacity of 50
13 PFArrayDBak(int capacityValue);
14 PFArrayDBak(const PFArrayDBak& Object);
15 void backup( );
16 //Makes a backup copy of the partially filled array
17 void restore( );
18 //Restores the partially filled array to the last saved version
19 //If backup has never been invoked, this empties the partially filled
20 //array
21 PFArrayDBak& operator =(const PFArrayDBak& rightSide);
22 ~PFArrayDBak( );
23 private:
24 double *b; //for a backup of main array
25 int usedB; //backup for inherited member variable used
26 };
27 #endif //PFARRAYD_H
Trang 6Display 14.11 Implementation for the Derived Class PFArrayDBak (part 1 of 2)
1 //This is the file pfarraydbak.cpp
2 //This is the implementation of the class PFArrayDBak
3 //The interface for the class PFArrayDBak is in the file pfarraydbak.h
4 #include "pfarraydbak.h"
5 #include <iostream>
6 using std::cout;
7 PFArrayDBak::PFArrayDBak( ) : PFArrayD( ), usedB(0)
8 {
9 b = new double[capacity];
10 }
11 PFArrayDBak::PFArrayDBak(int capacityValue) : PFArrayD(capacityValue), usedB(0)
12 {
13 b = new double[capacity];
14 }
15 PFArrayDBak::PFArrayDBak(const PFArrayDBak& oldObject)
16 : PFArrayD(oldObject), usedB(0)
17 {
18 b = new double[capacity];
19 usedB = oldObject.usedB;
20 for (int i = 0; i < usedB; i++)
21 b[i] = oldObject.b[i];
22 }
23 void PFArrayDBak::backup( )
24 {
25 usedB = used;
26 for (int i = 0; i < usedB; i++)
27 b[i] = a[i];
28 }
29
30 void PFArrayDBak::restore( )
31 {
32 used = usedB;
33 for (int i = 0; i < used; i++)
34 a[i] = b[i];
35 }
36 PFArrayDBak& PFArrayDBak::operator =(const PFArrayDBak& rightSide)
37 {
38 PFArrayD::operator =(rightSide);
39 if (capacity != rightSide.capacity)
Note that b is a copy of the array a
We do not want to use b = a;
You use a call to the base class assignment operator in order to assign to the base class member variables
Trang 7The member function backup copies data from the partially filled array (a and used) to the backup locations b and usedB with the following code:
usedB = used;
for (int i = 0; i < usedB; i++)
b[i] = a[i];
You should note that the member variables a and used in the base class are protected and not private Otherwise, the above code would be illegal because it accesses the inherited member variables a and used by name
The member function restore simply reverses things and copies from b and usedB to a and
used
The definition of the overloaded assignment operator for the derived class PFArrayDBak begins with an invocation of the assignment operator for the base class PFArrayD This copies all the data from the member variables a, used, and capacity from the object on the right-hand side
of the assigment operator (from the parameter rightSide) to the object on the left-hand side of the assignment operator (the calling object) We are relying on the fact that this was done prop-erly in the definition of the overloaded assignment operator in the base class That is, we rely on the base class assignment operator to behave correctly when the same object (for the inherited part) occurs on both sides of the assignment operator, and we assume that the copying actions make an independent copy of the array a The code in the body of the overloaded assignment operator for the derived class PFArrayDBak needs to create a similarly independent copy of the array b
Since the objects on the right and left sides of the assignment operators may have different capacities, we must create a new array b (in most cases) This is done as follows:
if (capacity != rightSide.capacity)
{
Display 14.11 Implementation for PFArrayDBak Class (part 2 of 2)
42 b = new double[rightSide.capacity];
44 usedB = rightSide.usedB;
45 for (int i = 0; i < usedB; i++)
46 b[i] = rightSide.b[i];
47 return *this;
48 }
49 PFArrayDBak::~PFArrayDBak( )
50 {
51 delete [] b;
52 }
The destructor for the base class PFArrayD is called automatically, and it performs delete [] a;
Trang 8delete [] b;
b = new double[rightSide.capacity];
}
Note that the Boolean expression in the if statement ensures thatb will not be deleted when the objects on either side of the assignment operator have the same capacity In particular, this ensures that when the same object appears on both sides of the assignment operator, the array b
is not deleted After this, the copying of data is routine
Note that the destructor for the class PFArrayDBak has no explicit mention of the inherited member variable a It simply sends the b array memory back to the freestore for recycling with the following:
delete [] b;
The memory for the inherited array a is also sent back to the freestore, even though you do not see any mention of a in the destructor for the derived class PFArrayDBak When the destructor for the derived class PFArrayDBak is invoked, it ends its action by automatically invoking the destructor for the base class PFArrayD, and that destructor includes the following code to dis-pose of a:
delete [] a;
A demonstration program for our class PFArrayDBak is given in Display 14.12
Display 14.12 Demonstration Program for the Class PFArrayDBak (part 1 of 3)
1 //Program to demonstrate the class PFArrayDBak
2 #include <iostream>
3 #include "pfarraydbak.h"
4 using std::cin;
5 using std::cout;
6 using std::endl;
7 void testPFArrayDBak( );
8 //Conducts one test of the class PFArrayDBak
9 int main( )
10 {
11 cout << "This program tests the class PFArrayDBak.\n";
12 char ans;
13 do
Trang 9Display 14.12 Demonstration Program for the Class PFArrayDBak (part 2 of 3)
17 cin >> ans;
18 }while ((ans == 'y') || (ans == 'Y'));
19 return 0;
20 }
21 void testPFArrayDBak( )
22 {
23 int cap;
24 cout << "Enter capacity of this super array: ";
25 cin >> cap;
26 PFArrayDBak a(cap);
27 cout << "Enter up to " << cap << " nonnegative numbers.\n";
28 cout << "Place a negative number at the end.\n";
29 double next;
30 cin >> next;
31 while ((next >= 0) && (!a.full( )))
33 a.addElement(next);
34 cin >> next;
36 if (next >= 0)
38 cout << "Could not read all numbers.\n";
39 //Clear the unread input:
40 while (next >= 0)
41 cin >> next;
43 int count = a.getNumberUsed( );
44 cout << "The following " << count
45 << " numbers read and stored:\n";
46 int index;
47 for (index = 0; index < count; index++)
48 cout << a[index] << " ";
49 cout << endl;
50 cout << "Backing up array.\n";
51 a.backup( );
52 cout << "Emptying array.\n";
Trang 10Display 14.12 Demonstration Program for the Class PFArrayDBak (part 3 of 3)
53 a.emptyArray( );
54 cout << a.getNumberUsed( )
55 << " numbers are now stored in the array.\n";
56 cout << "Restoring array.\n";
57 a.restore( );
58 count = a.getNumberUsed( );
59 cout << "The following " << count
60 << " numbers are now stored:\n";
61 for (index = 0; index < count; index++)
62 cout << a[index] << " ";
63 cout << endl;
64 }
SAMPLE DIALOGUE
This program tests the class PFArrayDBak
Enter capacity of this super array: 10
Enter up to 10 nonnegative numbers
Place a negative number at the end
1 2 3 4 5 -1
The following 5 numbers read and stored:
1 2 3 4 5
Backing up array
Emptying array
0 numbers are now stored in the array
Restoring array
The following 5 numbers are now stored:
1 2 3 4 5
Test again? (y/n) y
Enter capacity of this super array: 5
Enter up to 5 nonnegative numbers
Place a negative number at the end
1 2 3 4 5 6 7 -1
Could not read all numbers
The following 5 numbers read and stored:
1 2 3 4 5
Backing up array
Emptying array
0 numbers are now stored in the array
Restoring array
The following 5 numbers are now stored: