2.19 Changing Structure Contents
My first and my rest
I like to keep them to myself:
That is privacy
2.19.1 Objectives
what encapsulation is
use object variables
use the private designation in C++
2.19.2 Exercises (due 2011/11/30 08:45:00)
1. Create a program called fileCount that reads a file and prints how many characters, words, and lines it contains. This program may only read the file once. Write in accumulator style.
2. Redo fileCount with object variable mutation.
3. Develop a data definition for Hangman bodies, which are lists of parts. Write a function called ripper which returns a body with one less part.
4. Develop a data definition for Hangman words, which are lists of characters. Make a list of Hangman words and a function called randomWord which takes a list and returns a random word in it. Hint: To get random numbers in C, do this...
#include <stdio.h> |
#include <stdlib.h> |
#include <math.h> |
#include <time.h> |
|
int main () { |
// Put in the main() function |
srand ( time(NULL) ); |
// If you don't do it, then rand() will always return |
// the same sequence of numbers |
|
// rand() returns a random number |
// rand() % N chops it to the range [0,N) |
printf("The answer is %d, but should be %d\n", |
rand() % 50, |
24 ); |
|
} |
5. Develop a function called reveal which consumes two Hangman words (the target and the current) and a character (the guess) and returns a boolean that is true if the guess is in the target. In every position the target contained the guess, the current should be modified to contain the guess.
6. Develop a program called hangman which plays a game of Hangman with the user at the console. You should print out the current word and the body parts every round and allow the user to input a guess character. If the user guesses incorrectly, a body part should be removed. The game ends in success if the user guesses the word. The game ends in failure if the user loses all their body parts. The current should start off as ’_’. You should make the target randomly selected.
Hint: stdin is a C variable that is like the FILE the user is creating as they type. That is, getc(stdin) is like reading a file but communicates with a user. However, everytime the user presses a letter, they must press Return for the program to receive it. The Return will also be sent to the program, so the program should ignore every other getc.
2.19.3 Optional Exercises (due 2011/12/05 08:45:00)
7. Develop a data definition for intersections with four traffic lights. Develop a function called rotate that advances the entire intersection’s state to the next appropriate configuration. Make sure perpendicular directions aren’t green at the same time! Do not use mutation.
8. Rewrite rotate with mutation.
9. Protect your intersection’s state with private. You should show a possible attacker and how their attack is thwarted. Such an attacker will fail to compile, so you should put it in a comment and describe how the attack works and how you block it.
2.19.4 Notes
These notes are primarily for my sake, but I don’t see any reason to hide them from you.
We should always prefer internal mutation, like factorial, over external mutation, but external mutation is used to build internal, so we must understand it well. |
|
Can we re-use factorial? What if we wanted to find two factorials? [Yes, do it] |
|
Can we re-use 'next'? What if we wanted to manage two lights? [No, there's only one 'color'.] |
-- Okay, well duplicate it |
-- Copy the code so that you have colorAtUniversity and colorAtState, nextAtUniversity and nextAtState |
-- This will be tedious, hideous and ugly. |
|
Where have we seen re-use before? [With objects] |
-- Move the original code into a new TrafficLight class (but keep the static variable!!!!) |
-- Now, we have lightAtUniversity and lighAtState |
-- But we can't look at the color in our main function |
-- Write a method that gives you the color |
-- Now we can finally test |
-- But, when we call ->next() on one it affects the other!! |
|
Translate the static variable into a class variable |
-- [I don't know if this is true] say that we have to just name the new piece, but put its definition inside the constructor, just like we did with the other pieces |
-- We can't juse write "color = ..." anymore, we MUST write "this->color = ..." [I know that's wrong, but it is pedagogic to make it clear that it is a PIECE of the implicit argument.] |
-- This is a hint of how constructors can really do arbitrary computations and how objects can have more pieces |
-- Now the tests pass |
|
Elaborate on the mutation of structure contents |
-- Now that we made 'color' an attribute, we can write lightAtUniversity.color rather than lightAtUniversity->whatIsTheColor() |
-- Well, if we can write "this->color = "green"", can we write "lightAtUniversity->color = "green""? |
-- Is that good or bad? |
|
It is HORRIFIC: |
lightAtUniversity->color = "purple" |
|
Our code will NEVER recover. |
|
Mutation allows OTHERS to break our invariants---that the color is always green, red, or yellow. |
|
Introduce 'private' |
-- So far everything has been public |
-- But because of mutation it is clear that this is unsafe |
-- Instead, everything should be private and we should provide methods to give access to the pieces we want |
|
Show that this protects... |
const char* theColor = lightAtUniversity->whatIsTheColor(); |
theColor = "purple" |
printf("The light is %s, but should be %s\n", lightAtUniversity->whatIsTheColor(), "green"); |
// NOT purple! |
|
This is _encapsulation_ |
|
Make a new PhoneBook class (separate from ListOfPhoneEntry) that implements add and lookup |
Create a two phone books |
|
**** Show a small cyclic list and that it causes simple functions to not return. Say that dealing with cyclic data is complicated and we won't cover it. |
|
-- |
|
|
[This day is deliberately short, because yesterday might have run long and this is really complicated.] |
|
Some structures are inherently mutable and cannot be constructed any other way. |
|
An array is a homogeneous vector of values. |
|
Introduce 'for' |
|
Write sumArray (int[]) |
|
Show that it is a length-polymorphic |
-- This is why arrays exist, the same thing cannot be done with structures because they always have the same number of pieces |
-- However, how do we know how long it the array is? |
-- Safe array usage always combines the array with its length |
-- Sometimes in a struct |
-- How can you make sure the length is honest? |
|
Write sums |
-- Replaces each element with itself added to all subsequent elements |
-- Write in accumulator style with a helper |
-- Translate to a for form |
-- Why: We can count down, we can develop with accumulator style and translate, even though there is other mutation going on |
|
Write andArray (boolean[]) |
-- We can have arrays of everything |
|
Write inPlaceSort (int[]) |
-- Refer to http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-53.html (figures 126 and 127, for a refresher) |
|
== Congrats == |
|
You are a programmer! Go forth and conquer. |
|
Everything else is just learning the domains of existing libraries people have put together. |