1. Yes. You can plug in an object of a derived class for a parameter of the base class type. An HourlyEmployee
is an Employee
. A SalariedEmployee
is an Employee
.
class SmartBut : public Smart
{
public:
SmartBut( );
SmartBut(int newA, int newB, bool newCrazy);
bool isCrazy( ) const;
private:
bool crazy;
};
3. It is legal because a
and b
are marked protected
in the base class Smart
and so they can be accessed by name in a derived class. If a
and b
had instead been marked private
, then this would be illegal.
4. The declaration for the function getName
is not given in the definition of SalariedEmployee
because it is not redefined in the class SalariedEmployee
. It is inherited unchanged from the base class Employee.
#include <iostream>
#include "salariedemployee.h"
using namespace std;
namespace employeessavitch
{
class TitledEmployee : public SalariedEmployee
{
public:
TitledEmployee( );
TitledEmployee(string theName, string theTitle
string theSSN, double theSalary);
string getTitle( ) const;
void setTitle(string theTitle);
void setName(string theName);
private:
string title;
};
}//employeessavitch
namespace employeessavitch
{
TitledEmployee::TitledEmployee( )
: SalariedEmployee( ), title("No title yet")
{
//deliberately empty }
TitledEmployee::TitledEmployee(string theName,
string theTitle,
string theSSN, double theSalary)
:SalariedEmployee(theName,theSSN,theSalary),
title(theTitle)
{
//deliberately empty
} void TitledEmployee::setName(string theName)
{
Employee::setName(title + theName);
}
}//employeessavitch
7. No. If you do not define an overloaded assignment operator or a copy constructor for a derived class, then a default assignment operator and a default copy constructor will be defined for the derived class. However, if the class involves pointers, dynamic arrays, or other dynamic data, then it is almost certain that neither the default assignment operator nor the default copy constructor will behave as you want them to.
8. The constructors are called in the following order: first Parent
, then Child
, and finally Grandchild
. The destructors are called in the reverse order: first Grandchild
, then Child
, and finally Parent
.
//Uses iostream and cstdlib:
void PartFilledArray::addValue(double newEntry)
{
if (numberUsed == maxNumber)
{
cout << "Adding to a full array.\n";
exit(1);
}
else
{
a[numberUsed] = newEntry;
numberUsed++;
}
}
PartFilledArray::PartFilledArray
(const PartFilledArray& object)
: maxNumber(object.maxNumber),
numberUsed(object.numberUsed)
{
a = new double[maxNumber];
for (int i = 0; i < numberUsed; i++)
a[i] = object.a[i];
}
void PartFilledArray::operator =
(const PartFilledArray& rightSide)
{
if (rightSide.maxNumber > maxNumber)
{
delete [] a;
maxNumber = rightSide.maxNumber;
a = new double[maxNumber];
}
numberUsed = rightSide.numberUsed;
for (int i = 0; i < numberUsed; i++)
a[i] = rightSide.a[i];
}
PartFilledArray::~PartFilledArray()
{
delete [] a;
}
class PartFilledArrayWMax : public PartFilledArray
{
public:
PartFilledArrayWMax(int arraySize);
PartFilledArrayWMax(const PartFilledArrayWMax& object);
~PartFilledArrayWMax();
void operator= (const PartFilledArrayWMax& rightSide);
void addValue(double newEntry);
double getMax();
private:
double maxValue;
};
PartFilledArrayWMax::PartFilledArrayWMax(int arraySize)
: PartFilledArray(arraySize)
{
//Body intentionally empty.
//MaxValue uninitialized, since there
//is no suitable default value.
}
/*
Note that the following does not work, because it calls the default constructor for PartFilledArray, but PartFilledArray has no default constructor: PartFilledArrayWMax::PartFilledArrayWMax(int arraySize) : maxNumber(arraySize), numberUsed(0)
{
a = new double[maxNumber];
}
*/
PartFilledArrayWMax::PartFilledArrayWMax
(const PartFilledArrayWMax& object)
: PartFilledArray(object)
{
if (object.numberUsed > 0)
{
maxValue = a[0];
for (int i = 1; i < numberUsed; i++)
if (a[i] > maxValue)
maxValue = a[i];
}//else leave maxValue uninitialized
}
//This is equivalent to the default destructor supplied
//by C++, and so this definition can be omitted.
//But, if you omit it, you must also omit the destructor
//declaration from the class definition.
PartFilledArrayWMax::~PartFilledArrayWMax()
{
//Intentionally empty.
}
void PartFilledArrayWMax::operator =
(const PartFilledArrayWMax& rightSide)
{
PartFilledArray::operator =(rightSide);
maxValue = rightSide.maxValue;
}
//Uses iostream and cstdlib:
void PartFilledArrayWMax::addValue(double newEntry)
{
if (numberUsed == maxNumber)
{
cout << "Adding to a full array.\n";
exit(1);
}
if ((numberUsed == 0) || (newEntry > maxValue))
maxValue = newEntry;
a[numberUsed] = newEntry;
numberUsed++;
}
double PartFilledArrayWMax::getMax()
{
return maxValue;
}
11. The output would change to
Discounted item is not cheaper.
12. There would be no member to assign to the derived class’s added members.
13. Although it is legal to assign a derived class object to a base class variable, this discards the parts of the derived class object that are not members of the base class. This situation is known as the slicing problem.
14. If the base class function carries the virtual
modifier, then the type of the object to which the pointer was initialized determines whose member function is called. If the base class member function does not have the virtual
modifier, then the type of the pointer determines whose member function is called.