new
Suppose that the derived class uses new
:
// derived class with DMA
class hasDMA :public baseDMA
{
private:
char * style; // use new in constructors
public:
...
};
In this case, of course, you do have to define an explicit destructor, copy constructor, and assignment operator for the derived class. Let’s consider these methods in turn.
A derived class destructor automatically calls the base-class destructor, so its own responsibility is to clean up after what the derived-class constructors do. Thus, the hasDMA
destructor has to free the memory managed by the style
pointer and can rely on the baseDMA
destructor to free the memory managed by the label
pointer:
baseDMA::~baseDMA() // takes care of baseDMA stuff
{
delete [] label;
}
hasDMA::~hasDMA() // takes care of hasDMA stuff
{
delete [] style;
}
Next, consider copy constructors. The baseDMA
copy constructor follows the usual pattern for arrays of char
. That is, they use strlen()
to find the length needed to hold the C-style string, allocate sufficient memory (the number of characters plus one byte for the null character), and use the strcpy()
function to copy the original string to the target:
baseDMA::baseDMA(const baseDMA & rs)
{
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label, rs.label);
rating = rs.rating;
}
The hasDMA
copy constructor only has access to hasDMA
data, so it must invoke the baseDMA
copy constructor to handle the baseDMA
share of the data:
hasDMA::hasDMA(const hasDMA & hs)
: baseDMA(hs)
{
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
}
The point to note is that the member initializer list passes a hasDMA
reference to a baseDMA
constructor. There is no baseDMA
constructor with a type hasDMA
reference parameter, but none is needed. That’s because the baseDMA
copy constructor has a baseDMA
reference parameter, and a base class reference can refer to a derived type. Thus, the baseDMA
copy constructor uses the baseDMA
portion of the hasDMA
argument to construct the baseDMA
portion of the new object.
Next, consider assignment operators. The baseDMA
assignment operator follows the usual pattern:
baseDMA & baseDMA::operator=(const baseDMA & rs)
{
if (this == &rs)
return *this;
delete [] label;
label = new char[std::strlen(rs.label) + 1];
std::strcpy(label, rs.label);
rating = rs.rating;
return *this;
}
Because hasDMA
also uses dynamic memory allocation, it, too, needs an explicit assignment operator. Being a hasDMA
method, it only has direct access to hasDMA
data. Nonetheless, an explicit assignment operator for a derived class also has to take care of assignment for the inherited base class baseDMA
object. You can accomplish this by explicitly calling the base class assignment operator, as shown here:
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if (this == &hs)
return *this;
baseDMA::operator=(hs); // copy base portion
delete [] style; // prepare for new style
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
return *this;
}
The following statement might look a little odd:
baseDMA::operator=(hs); // copy base portion
But using function notation instead of operator notation lets you use the scope-resolution operator. In effect, the statement means the following:
*this = hs; // use baseDMA::operator=()
But, of course, the compiler ignores comments, so if you used the latter code, the compiler would use hasDMA::operator=()
instead and create a recursive call. Using function notation gets the correct assignment operator called.
In summary, when both the base class and the derived class use dynamic memory allocation, the derived-class destructor, copy constructor, and assignment operator all must use their base-class counterparts to handle the base-class component. This common requirement is accomplished three different ways. For a destructor, it is done automatically. For a constructor, it is accomplished by invoking the base-class copy constructor in the member initialization list, or else the default constructor is invoked automatically. For the assignment operator, it is accomplished by using the scope-resolution operator in an explicit call of the base-class assignment operator.
18.224.54.136