Please send questions to
st10@humboldt.edu .
Adding mutation to our classes...
* overloading - you can have multiple methods
with the same name in a class, as long as the
the headers for those methods are sufficiently
different (different number of parameters,
significantly-different-enough types of
parameters if one has methods with the same
number of parameters)
* ..you don't have to think of even more
good names for similar actions...
...or remember as many method names...
...or recognize them
SO -- a method that changes a data field of
a class instance is sometimes/often
called a modifier (or setter, or mutator, etc.)
method;
* when designing a class, you need to provide
a modifier method for each data field that
a user can reasonably be allowed to change;
CLASS STYLE STANDARD:
* for "plain vanilla" modifier functions,
that simply allow a user to set a class data
field to a value of their choice,
you are expected to name these using the
pattern:
set_<data_field_name> (or set<Data_field_name>)
So, for boa, let's say we want the user to be
able to change all 3 data fields of a boa
instance.
The modifier methods should (based on the above)
be:
set_length (also OK: setLength)
set_color (also OK: setColor)
set_food (also OK: setFood)
* since a modifier method is intended to let the user change
a data field's value -- how does the user indicate that?
...with a parameter intended to contain the desired new
value; (give it a *descriptive* name DIFFERENT from
the data field name...)
* since the point with a modifier method is simply to
change the data field, this method doesn't need to
produce anything --
* but a C++ function or method needs to have a return
type;
* fortunately, C++ has a keyword indicating nothing is
to be returned -- void!
* SO, when a function or method's purpose is just to have
a side-effect -- and not produce/return anything -- it
should have a return type of void
* SO -- here are some good method headers for boa's
modifier methods -- add these to the public part of
boa's class definition in boa.h:
void set_length(double new_length);
void set_color(string new_color);
void set_food(string new_food);
* and add their implementations to boa.cpp --
* remember to add boa:: in front of the method names in their
headers in boa.cpp!
* DON'T put a semicolon after the header when implementing
the method in boa.cpp!
* and really, all these need to do is to *assign* the desired
new value to the appropriate data field -- for example,
void boa::set_length(double new_length)
{
length = new_length;
}
* and now -- these need to be tested!
* need to add tests for the modifier methods to boa_test.cpp;
* basically: call each modifier method to change something
in an instance of the class, and then check that all of the
data fields have indeed been changed;
* now it becomes easier if we make some bool variables to hold
different sets of tests -- here the selector tests and the
modifier tests -- and then return the result of and'ing those
test results;
* that is, add these bool variables to boa_test, after george's
declaration:
// these are to keep track of my test results
bool selector_results;
bool modif_results;
* then change the current return statement to instead set
selector_results:
selector_results =
(george.get_color() == "fuschia") and
(george.get_length() == 50) and
(george.get_food() == "crocodiles");
* now call each modifier on george (on your instance), changing
each of that instance's data fields -- for example,
// exercise the modifier methods
george.set_color("purple");
george.set_length(75);
george.set_food("dragons");
* ...and set modif_results to the result of comparing all
the data field values to what they should be now:
modif_results =
(george.get_color() == "purple") and
(george.get_length() == 75) and
(george.get_food() == "dragons");
* and NOW return the result of and'ing selector_results and
modif_results:
return (selector_results and modif_results);
* compile, and see if you get true when you run boa_test...!
ZERO-ARGUMENT CONSTRUCTOR:
* ...it is considered GOOD PRACTICE to always
provide a zero-argument constructor for a class;
(there are times when C++ automatically creates
a class instance "for" you, and a 0-argument
constructor makes this less awkward...)
* if we add a 0-argument boa constructor,
we're overloading the boa constructor --
we're providing 2 with the same name
* SO -- what do we add to boa.h?
...in the public: part of the boa class definition,
preferably right around where you defined the 3-argument boa
constructor, add the definition for the 0-argument one:
boa( );
* And, what do we add to boa.cpp?
...its implementation -- and since the user isn't specifying
values for the data fields, we need to assign DEFAULT values
to each;
...(don't forget the boa:: before the constructor name!)
...often, you might set a string data field to "" (the empty string)
or a numeric data field to 0 -- here, we're being a little more
whimsical. You should decide on reasonable default data field values
based on the setting your program is being used in.
...we ended up with:
boa::boa( )
{
color = "green";
length = 6;
food = "alligators";
}
* but, again -- gotta TEST this!
And this brings up an IMPORTANT C++ SYNTAX QUIRK --
when you make a declaration of a variable using a 0-argument
constructor, you need to OMIT the usual empty parentheses!
* so, to declare a boa named carol using the 0-argument
constructor, you use:
boa carol;
(not the typical 0-argument function call style of boa carol( );)
(can you see that boa carol( ); // DOES NOT WORK
also looks like a function header for a function carol that
expects nothing and produces a boa? That ambiguity makes it
unacceptable...thus this syntax quirk!)
* So -- we'll declare carol as shown above to boa_test.cpp,
and then add tests making sure that its data fields are what
the 0-argument should set them to to the expression setting
selector_results:
selector_results =
(george.get_color() == "fuschia") and
(george.get_length() == 50) and
(george.get_food() == "crocodiles") and
(carol.get_color() == "green") and
(carol.get_length() == 6) and
(carol.get_food() == "alligators");
...and compile boa_test, and make sure it produces true...
* next, adding some OTHER methods to boa...