Fall 2006

Clay Shields


front | classes | research | personal | contact

Parker's Implacable Camera, Co.

Assigned: November 21st
Program source code due: December 5th

Update

I am planning on testing your code by using a main function that tests the various methods in the Image class and Photo_set class. So it isn't a surprise (and to catch any bugs I might have in my main ahead of time) I am making this main available to you. You can download the file named grading-main.cc. You can put this in your code and it will to some more thorough test than the other mains, and print out a score out of 75.

You can also copy the grading-main.cc file to your account on seva by typing:

cp ~clay/grading-main.cc ~/

once it is on your account, assuming that your file is named picco-ll.cc you can insert it into your code easily by doing this:

cat grading-main.cc >> picco-ll.cc

That will append it to the end of the picco-ll.cc file.

If you get any error messages that you think are incorrect, let me know what the message was and send me your code.

Please remove this main from the code before submitting your projects!

Parker's Implacable Camera, Co. - Old School, with pointers


On a recommendation from Sid, Parker of Parker's Implacable Camera Co. (Motto - "Getting all the pictures of your wedding day, even the ones you don't want. As seen on Springer!") has contacted you about coming up with a program that allows customers to look through a list of photos and select which ones they would like to order. To help you do this, an outline of a program has been provided for you. You can download this file here, or copy it to your account on seva by typing:

cp ~clay/picco-ll-clean.cc ~/

You can run a working version of this program by typing:

~clay/picco-ll

but you won't notice any difference from the last project. Yes, this is the same project as before, but this time with linked lists replacing where we used vectors last time. The Image class will be made into a self-referential class, and the photo_set class will use the changed Image class. I have broken this up into steps to help you, much like the last project.

Step 1 First, we are going to make the Image class self referential by adding a pointer to another Image in side of it. Here is what the class definition looks like, minus what you need to add:

 

class Image{

  friend ostream &operator<<(ostream &, Image);
  friend istream &operator>>(istream&, Image &);

public:
  // Default constructor  
  Image();
  // Constructor with initial values
  Image(string, string);
  // Name observer
  string get_name();
  // Tags observer
  string get_tags();
  //Accesor for the tags. 
  void set_tags(string);
  // Acessor for the name
  void set_name(string);
  //nextImage observer
  Image * get_next_image();
  //nextImage accessor
  void set_next_image(Image *);
  // Image destructor
  ~Image();

private:
  string image_name;
  string image_tags;
  Image * nextImage;
};

// Default constructor
Image::Image(){

  // MAKE THIS WORK

}

// Initializing Constructor
// Initialize things nicely
Image::Image(string initial_name, string initial_tags){

    // MAKE THIS WORK
  
}

// Return the image name
string Image::get_name(){

  return image_name;
  
}

// Return the tags
string Image::get_tags(){

  return image_tags;

}

// Change the tags
void Image::set_tags(string new_tags){

  image_tags = new_tags;

}

// Change the name
void Image::set_name(string new_name){

  image_name = new_name;

}


//Find out what the next image is
Image * Image::get_next_image(){
  
  // MAKE THIS WORK

}

// Set the next image to what is passed as a parameter
void Image::set_next_image(Image * new_image){

  // MAKE THIS WORK

}


Image::~Image(){
  
  // MAKE THIS WORK
  
}

ostream &operator<<(ostream & output, Image i){
  
  output << i.image_name << " " << i.image_tags;

};


istream &operator>>(istream& input, Image & i){

  input >> i.image_name;
  input.ignore();
  getline(input,i.image_tags);
  i.nextImage = NULL;
};


Your first task is to fill in the code above. To make sure it works, test it with the main function below. This function is commented out in the file provided with C style comments. Note that looking at these main functions is a good way to see how the objects work.

 

int main(){

  // A small main program to test the image class

  // Create a new image
  Image test_image("DSCF0020","Bride, groom, close up");
  // make sure the observors work
  cout << "Testing observors:" << endl;
  cout << "This should say DSCF0020: " << test_image.get_name() << endl;
  cout << "This should say 'Bride, groom, close up': " << test_image.get_tags() << endl;
  // make sure the accesor for the tags works:
  cout << "Testing accessors:" << endl;
  test_image.set_tags("Bride, groom, close up, pimple");
  cout << "This should say 'Bride, groom, close up, pimple': " << test_image.get_tags() << endl;
  // make sure the friend functions work as well
  cout << "The next line should say 'DSCF0020 Bride, groom, close up, pimple':"  << endl;
  cout << test_image << endl;
  // now test the input operator
  cout << "At the prompt, please type - D01 Bride, groom, family:" << endl;
  cin >> test_image;
  cout << "The next line should say 'D01 Bride, groom, family':"  << endl;
  cout << test_image << endl;
  cout << test_image.get_tags() << endl;

  // Some new tests to make sure that the nextImage stuff works
  
  cout << "Testing pointer part" << endl << endl;

  Image * testPtr = new Image("DSC099.JPG","Grooms Father making a toast");
  cout << " The next line should say: DSC099.JPG Grooms Father making a toast" 
         << endl;
  cout << *testPtr << endl;
  
  Image * otherPtr = new Image("DSC100.JPG","Everyone toasting");
  
  testPtr->set_next_image(otherPtr);

  cout << "The next line should say DSC100.JPG Everyone toasting" << endl;
  cout << * testPtr->get_next_image() << endl;

}

Step 2

Once you have that working, it is time to do the Photo_set class. I have provided an outline of the class below:



class Photo_set{

public:
  // Default constructor for empty photo set
  Photo_set();
  // Method that loads the Image names and tags from a file
  void load_set(string source_file);
  // Show a numbered list of images
  void display_images();
  // return a copy of one of the images in the set
  Image extract_image(int);
  // Add an image to the set
  void add_image(Image);
  // Return the number of images
  int number_of_images();
  // Return the name of the set
  string get_name();
  // Set the name of the photo set
  void change_set_name(string);
  // Save the photo set into a file
  void save_set(string);
  // Destroy the photo set
  ~Photo_set();
  
private:
  string set_name;
  Image * images;
  // A small method to add a dynamically created image to the list
  // Here because we want to separate out operations that happen
  // in more than one method.
  void add_image_to_list(Image *);
  // A small method to delete the list
  // Again, used in different public methods.
  void clear_list();
};

// A default constructor that makes a blank set
Photo_set::Photo_set(){

  // MAKE THIS WORK

}

// A method that is given the name of a file and reads
// the information from the file. 
// The file has the format:
// One line with the set name
// Many lines, each with one image on them
// Clear the old list when loading a new one.
// The private method clear_list is good for this
void Photo_set::load_set(string filename){

  // MAKE THIS WORK
  

}

// Display a numbered list of images contained in the photo set
// Start with the name, so we know which set it is
// Notice that numbering starts at 1, because we don't want to 
// confuse grandma
void Photo_set::display_images(){
  
  // MAKE THIS WORK
  
}


// Given an integer that represents a number from the display_images
// list, return a copy of that image
// It does not remove the extracted image from the list
// I test to make sure the image number is in range;
// if it isn't, the method prints an error message and exits.
// if it is out of range it will crash anyway. There are better
// ways of handling this, but they are more complicated than we care about
Image Photo_set::extract_image(int image_number){

  // MAKE THIS WORK

}

// Add an image to the set
// This is tricky because we need to only add dynamically created
// image objects; we can't add the parameter passed directly, as it is
// goes out of scope when the method ends
void Photo_set::add_image(Image new_image){

  // MAKE THIS WORK

}

// Return the number of images
// This is just the size of the vector
int Photo_set::number_of_images(){
  
  // MAKE THIS WORK
 
}

// Get name simply returns the name of the set
string Photo_set::get_name(){
  
  return set_name;

}

// Set the name of the photo set
void Photo_set::change_set_name(string new_name){
  
  set_name = new_name;
  
}

// Save the photo set into a file of the specified name
// It should save the set name and all the images
void Photo_set::save_set(string filename){
  
  // MAKE THIS WORK

}


// This is a private function that will add a pointer to a file to the
// image list. It needs to add to the end to keep the images ordered
// If you add to the front, they will be reversed
void Photo_set::add_image_to_list(Image * new_image){

  // MAKE THIS WORK

}

// This is a private function that will clear the list and
// set images to NULL
void Photo_set::clear_list(){

  // MAKE THIS WORK

}


// Destroy the photo set
// For this we need to delete all the items on the list
// since they live outside the object. If the object goes away without
// deleting them, we get a memory leak.
Photo_set::~Photo_set(){

  // MAKE THIS WORK

}

To help you with this, I have provided a main section that you can use to test the different methods in the class. This main is broken down into smaller steps. You can use it to write and test different methods a few at a time in order. Doing so will make your life easier.

///////////////////////////////////////////////////////////////////////////
// A main function to test that the photo_set class works
// This is done is steps to test different parts of the program.

int main(){
  
  // This section is set up so you can add methods one or two at a time
  // and then just change where the return 0 happens. 
  // It should be easier to work on and test a few things at a time


  // The first thing we test is the add_image method and the
  // display_images method.  I used the private add_image_to_list
  // method in my add_image, so that gets tested too
  
  Photo_set test_set;
  Image test_image ("DSC901.JPG","Cows");
  
  cout << "Adding image";
  test_set.add_image(test_image);
  cout << endl << "Done" << endl << "The next line should read:"
       << "1 DSC901.JPG Cows"<< endl;
  test_set.display_images();

  // Remove or comment out the line below when the above portion works
   return 0;

  // Now add some more images to better test the adding method and the printing
  // since adding can go wrong

  cout << "Adding image 2";
  test_image.set_name("DSC902.JPG");
  test_image.set_tags("Brown cows");
  test_set.add_image(test_image);
  cout << ".....done" << endl << "Adding image 3";
  test_image.set_name("DSC903.JPG");
  test_image.set_tags("White cows");
  test_set.add_image(test_image);
  cout << ".....done" << endl << "Adding image 4";
  test_image.set_name("DSC904.JPG");
  test_image.set_tags("Spotted cows");
  test_set.add_image(test_image);
  cout << ".....done" << endl;
  cout << endl;
  cout << "There should be four cow pictures below, in order by name" << endl;
  test_set.display_images();
  cout << endl;

  // Uncomment the line below until the above portion works
  // return 0;


  // Test the number_of_images method
  cout << "There should be 4 images, and there are: " << test_set.number_of_images() << endl;
  cout << endl;
  
  // Uncomment the line below until the above portion works
  // return 0;

  // test the extract image method
  // and the display again, to make sure it isn't removed
  
  Image result = test_set.extract_image(2);
  cout << "The next line should read:   DSC902.JPG Brown cows"  << endl;
  cout << result << endl;
  cout << endl;

  cout << "There should be four cow pictures below, in order by name" << endl;
  cout << "If there are fewer, extract removed from the list instead" << endl;
  cout << "returning a copy of the desired image." << endl;
  
  test_set.display_images();
  cout << endl;

  // Uncomment the line below until the above portion works
  // return 0;


  // test the save_set
  // You can look at the file named "test-ouput" in pico to make sure that
  // it is correct. It should say "Cow collection" then the same four images
  // we saw before
  test_set.change_set_name("Cow collection");
  test_set.save_set("test_output");

  // Uncomment the line below until the above portion works
  // return 0;

  // Test the load_set
  // We should be able to load the set we just saved
  Photo_set another_set;
  another_set.load_set("test_output");
  cout << "The set below should show our 4 cows" 
       << endl;
  another_set.display_images();
  cout << endl;

  // Uncomment the line below until the above portion works
  // return 0;


  // Load again to make sure the list is cleared

  another_set.load_set("test_output");
  cout << "The set below should show our 4 cows. If there are more, "
       << "you forgot to clear the list before loading new things in." 
       << endl;
  another_set.display_images();
  cout << endl;

  cout << "If all these worked, the main from the last project should"; 
  cout << "work now, without change." << endl;

  //return 0;

}


Step 3 Now you need to make a main that does what the last one did. Hey, guess what, because of the object-oriented design, no changes are needed. You are done.

What to turn in

Include the following header in your source code.

            //
            // Project 5
            // Name: <your name>
            // E-mail: <your e-mail address>
            // COSC 071
            //
            // In accordance with the class policies and Georgetown's
            // Honor Code, I certify that I have neither given nor
            // received any assistance  on this project with the
            // exceptions of the lecture notes and those  items noted
            // below.
            //
            //
            // Description: <Describe your program>
            //
          

You will submit your source code using the submit program. This is the .cc file. Do not submit the compiled version! I don't speak binary very well.

To submit your program, make sure there is a copy of the source code on your account on seva. You may name your program what you like - let's assume that it is called picco-ll.cc. To submit your program electronically, use the submit program like we did in Homework 2 and Project 1, 2, and 3, but with the command:

submit -a p5 -f picco.cc