Section 4 - Designing the Class
7B.4.1 The Member Data
There are two types of member data we saw we need:
- Instance members for the 3 doubles that describe a loan.
- Static class members that hold the extreme values of our data
We will add a new modifier, const, to our vocabulary. Since these static class variables are going to be constant, we will ensure this by declaring them to be so. This will prevent any inadvertent re-assignment or change to those static members. That is what the keyword const means.
Here is the portion of the MortgageData class that covers the definition of both the instance data and the static data:
class MortgageData
{
private:
double dblPrincipal;
double dblRate;
double dblYears;
public:
// class constants
static const double MIN_LOAN;
static const double MAX_LOAN;
static const double MIN_RATE;
static const double MAX_RATE;
static const double MIN_YRS;
static const double MAX_YRS;
// accessors
// (... omitted for now ...)
// constructors
// (... omitted for now ...)
};
// static member intialization
double const MortgageData::MIN_LOAN = 1.;
double const MortgageData::MAX_LOAN = 100000000.;
double const MortgageData::MIN_RATE = .00001;
double const MortgageData::MAX_RATE = 25.;
double const MortgageData::MIN_YRS = 1;
double const MortgageData::MAX_YRS = 100;
This is very common in a class. The important data is kept private. Data meant to be constants are public and are declared as const. They are commonly capitalized to emphasize their meaning as constants.
7B.4.2 Accessor Methods of the Class
Here are two class accessor (meaning accessor and/or mutator) methods, setRate() and getRate(). The remaining accessor methods setPrincipal(), getPrincipal(), setYears() and getYears() are defined similarly.
bool MortgageData::setRate (double rt)
{
if (rt < MIN_RATE || rt > MAX_RATE)
return false;
dblRate = rt;
return true;
}
double MortgageData::getRate()
{
return dblRate;
}
This is a good time to emphasize that the class methods do not have to use the class name to dereference the class variables. MIN_RATE and MAX_RATE in the above method demonstrate this point.
7B.4.3 Two Overloaded Constructors
We complete the picture by presenting the constructors for the class.
We have seen examples of constructor overloading with our Galaxy class. We do that again here. We define two separate constructors, one that takes no parameters (a default constructor) and one that takes three parameters. If the client passes parameters to the constructor in the instantiation line, then the 3-parameter constructor gets invoked. If not, the default constructor is called.
This can be done with any method, of course, not just constructor methods. But overloading constructors is a very powerful and common technique.
// constructors
MortgageData::MortgageData()
{
// default values (best to do this via mutators, if they exist)
dblPrincipal = 1;
dblRate = .001;
dblYears = 1;
}
MortgageData::MortgageData(double prin, double rt, double yr)
{
if (!setPrincipal(prin))
setPrincipal(1);
if (!setRate(rt))
setRate(.001);
if (!setYears(yr))
setYears(1);
}
So we can instantiate a MortgageData object either this way:
MortgageData loan1;
or this way:
MortgageData loan2(200000, 6.125, 30);
Also, note that the constructor makes use of the other mutator functions setPrincipal(), etc. There is no need to set the data of the class manually if we can use a mutator method that does the work of filtering the data. We don't have to test the data for validity again since it is already done for us in these mutators.
You should always reuse methods of classes this way. Duplicating logic leads to errors and makes your code longer than it need be.