CSE 109 Test 1  Wednesday  2 March 2005
>>>>>>>>>>>>>>>>>>>>>>>SUGGESTED ANSWERS<<<<<<<<<<<<<<<<<<<<<<<<<<<
1.  Assume that the file code.h contains the following three lines
      void test1();
      void test2();
      void test3();
    and assume that the file code.cc contains the code for the three fucntions
    declared in code.h.  Write a program that enables the entry of 1, 2, or 3
    on the command line and then calls either test1(), test2(), or test3(),
    depending on whether 1, 2, or 3 is entered. Your program should assume
    that the file code.cc is compiled separately.  If the executable code is
    stored in myProg, a legitimate call might be
       myProg 1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    #include <fstream.h>
    #include "code.h"
    void check(bool b,char *mess);
    int main(int ct,char *arg[])
    {check(ct==2,"Usage: myProg <digit>");
     check(arg[1][0]>='1' && arg[1][0]<='3' && arg[1][1]=='\0',
           "Argument should be '1', '2', or '3'");
     switch(arg[1][0])
     {case '1': test1(); break;
     case '2': test2(); break;
     case '3': test3(); break;
     }
     return 0;
    }
    void check(bool b, char*mess)
    {if(!b)
      {cout<<mess<<endl;
       exit(1);
      }
    }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2.  Write a makefile that assumes the program in question 1 is stored in
    prog.cc, that creates an executable file based on separate compilations of
    prog.cc and code.cc, and that stores the executable file in myProg.  The
    makefile should include a command "clean" that removes the .o files, the
    file myProg, and files with a twiddle (~) suffix.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
myProg: prog.o code.o
        g++ -o myProg prog.o code.o

prog.o: prog.cc code.h
        g++ -c -Wall -Werror prog.cc

code.o: code.cc code.h
        g++ -c -Wall -Werror code.cc

clean:
        rm -f *.o *~ myProg
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
3.  Our implementation of class Safe could only store ints.  It would be much
    better to specify the type of the variable being protected when the class
    is used. Thus, the class should be templated. For a templated class Safe
    arithmetic and logical comparisons would make little sense (they could be
    left for a subclass).  Write the template for a class Safe<> that does
    not enable arithmetic or logical comparisons.  You should have a complete
    declaration, but you need only write templated definitions(code) for one
    constructor (of your choice) and one member function (of your choice).
    Perhaps you will get the rest to do on the final examination.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <fstream.h>
template <class X>
class Safe
{public:
   Safe();
   Safe(const X&x);
   Safe(const Safe &x);
   ~Safe();
   void set(const X&x);
   X get()const;
   bool isValid()const;
   template <class Y>
   friend ostream & operator<<(ostream &out,const Safe<Y> & s);
 private:
   bool valid;
   X data;
   static void check(bool b,char *mess);
;
template <class X>
Safe<X>::Safe():valid(false){}

template <class X>
Safe<X>::Safe(const X&x):valid(true),data(x){}

template <class X>
Safe<X>::Safe(const Safe &x):valid(x.valid),data(x.data){}

template <class X>
Safe<X>::~Safe(){}

template <class X>
void Safe<X>::set(const X&x)
{data=x;
 valid=true;
}

template <class X>
X Safe<X>::get()const
{check(valid,"Undefined variable");
return data;}

template <class X>
bool Safe<X>::isValid()const
{return valid;}

template <class Y>
ostream & operator<<(ostream &out,const Safe<Y> & s)
{out<<s.get();
 return out;
}

template <class X>
void Safe<X>::check(bool b, char *mess)
{if(!b)
  {cerr<<"ERROR[Safe<>]: "<<mess<<endl;
   exit(1);
  }

}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
4.  Assume you have a class Safe like the one from programming assignment 2,
    except that it stores chars, rather than ints, and except that it does
    not implement arithmetic (but does implement logical comparisons). Write
    the declarations and definitions (code) for a subclass of class Safe,
    called Letters, that only allows storage and retrieval of upper and lower
    case letters ('a'...'z', 'A'...'Z').
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Just for fun (hey, I get fun out of such things) I will make this a subclass
of the templated class in 3.  It currently does not have templates for logical
comparisons, so assume that it does.  Such templates take the form
template <class Y>
bool operator<(const Safe<Y>&a,const Safe<Y>&b)
{return a.get()<b.get();}
//that is, get() checks whether the value is defined
Also, assume the "private" above is changed to "protected".
class Letters:public Safe<char>
{public:
  Letters();
  Letters(char ch);
  Letters(const Safe&s); //includes downcasting and copy constructor
                         //because Letters is a sublcass of Safe
  ~Letters();
  void set(char ch);
};

Letters::Letters(){}

Letters::Letters(char ch):Safe<char>(ch)
{check(ch>='a' && ch<='z' || ch>='A' && ch<='Z',
     "Letter out of range");
}

Letters::Letters(const Safe&s):Safe<char>(s)
{check(!valid || s.data>='a' && s.data<='z' || s.data>='A' && s.data<='Z',
    "Data out of range 'a'...'z', 'A'...'Z'");

}

Letters::~Letters(){}

void Letters::set(char ch)
{check(ch>='a' && ch<='z' || ch>='A' && ch<='Z',
     "Letter out of range");
 Save<char>::set(ch);
}
