UCLA PIC 10B,  Problem Solving using C++

Summer 2001,

 

Instructor: Ivo Dinov, Asst. Prof. In Mathematics/Neurology

 

Final Exam Study Guide

 

Wednesday, Aug. 15, 2001, 9:30 AM, PPB # 2214

 

Multiple choice questions may have more than one correct answer. Give all correct answers. If an answer to a multiple choice question is in some sense only partially correct, an explanation should be worth points. True - False questions require an explanation. This study guide is complementary to the MidTerm Study Guide (which is also available online at the PIC10B class notes page).

 

I.                Part One

 

1. Define or characterize the template facility for C++.

 

2. True or False: Templates allow only parameterized types for classes.

 

3. True or False: Templates allow only parameterized types for functions.

 

4. Templates may be used to make available a very large collection of _____.

 

        a) programs

        b) classes

        c) file

        d) functions

        e) none of the above. C++ doesn't support templates.

 

5. In the template prefix,

 

      template <class T>

 

What kind of variable is the parameter T?

 

        a. T must be a class

        b. T must not be a class

        c. T can be only types built into the C++ language

        d. T can be any type, whether built into C++ or declared by the client programmer.

 

6. True-False. A function template behaves as if the programmer had overloaded the function name for every type used in an instantiation.

 

7.  For the following template declaration of the following function,

 

      template<class T> void problem_7( T object);

 

                a. Give a statement that causes the compiler to generate a function that

                    passes int values to the function problem_7.

 

                b. Give an equivalent function declaration (prototype) for the function

                    generated by this usage.

 

8.  Write a function template for a function named minimum. The function will have two parameters of the same type. It returns the smaller of these (either if they are equal.)

 

In carrying this out, give:

 

      a. a prototype (declaration) and preconditions for the function template

      b. a definition for this function.

      c. As a part of your answer, remark on the restriction of this function template to types for which operator< defined.

 

9. Describe a strategy for writing template functions.

 

 

10. What is wrong with the following function template (Other than the fact that it really does almost nothing)?

 

  template<class T>

  void f( int & x )

  {

    return x;

  }

  int main()

  {

    int y = 3, z;

    z = f(y);

  }

 

11. How many type parameters may a function template have?

          a) none, that is not what the parameters in a function template are called.

          b) 1

          c) 2

          d) as many as are needed

 

 

The answer to next question is very compiler dependent.  It is based on the PITFALL: Compiler Complications in the text on page 754.  Use of this question requires investigation of problems with your compiler’s template facility.

 

12. The code for a template function is generated when:

 

          a) the function template declaration (prototype) appears in the C++ program.

          b) the function template is encountered in the C++ program.

          c) the function call is encountered in the C++ program

          d) at runtime, when the function call is executed.

 

 

13. What problems with templates have you encountered with regard to your compiler’s template facility?

 

14. True-False: In writing a class template, the function declarations within the class have special placement and special location.

 

15. True-False: In implementing class template member functions, the functions are themselves templates.

 

16. Given this (incomplete) class template below, complete the template and show how to implement the member function

  void f( T x );

 

Hint: What the function does is immaterial. I suggest you use this for the function body.

  {

    //whatever f does

  }

 

  template<class T>

  class Problem

  {

  public:

    . . .

    void f( T x );

  private:

    int x;

  };

 

17. True False: In the implementation of a class template function, the class name before the scope resolution operator is just the class name, with no additional syntax.

 

18. What if anything is wrong with the following code?

 

  template<class T>

  class A

  {

  public:

    A();

    ...

  private:

    ...

  };

 

  template<class T>

  A::A()

  {

    ...

  }

 

19. What if anything is wrong with the following code?

 

  template<class T>

  class A

  {

  public:

    A();

    ...

  private:

    ...

  };

 

  A<T>::A()

  {

    //...

  }

 

20. Discuss briefly, indicating whether mostly true or mostly false and justify:

                Friends are used exactly the same for template and non-template classes.

 

21.  Which of the following template function definitions and invocations will not compile, if any?  If not, why not?

 

          Assume that classes have been declared with appropriate

          default constructors and assume that

 

  //a.

  template<class A>

  A func( A x, A y){ return A(); }

  int main()

  {

    U u1, u2, u3;

    u2 =  func(u2, u3);

  }

 

  //b. 

  template<class B>

  B func() { return 1; }

  int main()

  {

    T t;

    t = f();

  }

 

  //c.

  template<class C>

  void func(C x, int * y){}

  int main()

  {

    T t;

    int i;

    func( t, &i );

  }

 

  //d.

  template<class D, class E>

  void func(D x, E y){}

 

  int main()

  {

    T t;

    U u;

    func ( t, u );

  }

 

 

II.           Part Two

 

1. A linked list is

                a) fixed in size

                b) can vary in size, shrinking or growing as there is need

                c) can be set, and then not changed other than destroying the list

                d) none of the above

 

2. Given the structure definition:

 

                const int STRING_SIZE = 20;

      struct ListNode

      {

            char item[STRING_SIZE];

            int count;

            ListNode * link;

      };

 

      ListNode * head = new ListNode;

 

Show two equivalent ways to set the count member in the ListNode variable to which head points.

 

3.  Given the structure definition:

 

                const int STRING_SIZE = 20;

      struct ListNode

      {

            char item[STRING_SIZE];

            int count;

            ListNode * link;

      };

 

      ListNode * head = new ListNode;

 

Give code to assign the string "Wilbur's brother Orville" to the member item of the variable to which head points. Hint: you need a function declared in cstring.

 

4. The link field in the last node in a linked list has a special value stored in it. What is it? It has a special name. What is the special name?  Why is this done?

 

5. Given the type definitions:

 

          const int STRING_SIZE = 20;

    struct ListNode

    {

      char item[STRING_SIZE];

      int count;

      ListNode * link;

    };

 

                What is the output produced by the following code? (As always,  you are to assume that

                the code is embedded in a correct and complete            program.

 

                ListNode * head = new ListNode;

                strcpy( head->item, "Stop Light");

      head->count = 10;

      cout << (*head).item << endl;

      cout << head->item << endl;

      cout << (*head).count << endl;

      cout << head->number << endl;

 

6.  Given the type definitions:

 

        const int STRING_SIZE = 20;

   struct ListNode

   {

      char item[STRING_SIZE];

      int count;

      ListNode * link;

   };

 

   ListNode * head = new ListNode[10];

 

Show how to return the store allocated by this statement to the heap manager for reallocation.

 

7. Given the type definitions:

 

        const int STRING_SIZE = 20;

   struct ListNode

   {

      char item[STRING_SIZE];

      int count;

      ListNode * link;

   };

 

   ListNode * head = new ListNode;

 

Give a typedef statement that hides the pointer operator *. Call the new type identifier NodePtr.

 

8. Which of the following are potential problems when we use the delete operator on a pointer variable.

                a) inaccessible heap memory

                b) dangling pointers

                c) uninitialized pointers

                d) NULL pointers

 

9. Which of the following are potential problems when we assign pointer variables:

                a) inaccessible heap memory

                b) dangling pointers

                c) uninitialized pointers

                d) NULL pointers

 

10.  Here is a diagram of a three node linked list with a head pointer and a node to be inserted. Show all steps necessary to insert the node pointed to by temp between the second and third nodes, including the search for the node prior to insertion.

 

You are to make clear the sequence of steps by either numbering the steps, or by making several copies of this drawing, with one change per drawing, numbered to show the sequence.

 

You may assume a search routine taking a head node and data has been defined for you.

 

Give code and the drawing to make absolutely clear what you are doing.

 

11.  Here is a diagram of a three node linked list with a head pointer and a node to be inserted. Show all steps necessary to delete the second node, pointed to by discard_me. You may assume the necessary search for the node to be deleted is done and the pointer discard_me is already positioned.

You are to make clear the sequence of steps by either numbering the steps, or by making several copies of this drawing, with one change per drawing, numbered to show the sequence.

You may assume that a search routine taking a head pointer and data arguments has been defined for you.

Give code and the drawing to make absolutely clear what you are doing.

 

                                NodePtr discard_me;

            NodePtr temp_ptr;

 

12. Answer, and explain: For large lists, inserting a new item into a linked list compared to insertion in an array is

                a) more efficient.

                b) less efficient.

                c) about the same.

                d) depends on the size of the two lists.

 

13.  Answer, and explain: For large lists, deleting an item from a linked list compared to deletion from an array is

                a) more efficient.

                b) less efficient.

                c) about the same.

                d) depends on the size of the two lists.

 

14. A linked list is normally specified by giving a pointer pointing to the first node of a list. An empty list has no nodes at all. What is the value of a head pointer for an empty list?

 

15. Suppose you have the following struct definition and typedef statements in your program:

 

                struct N

      {

            double d;

            N* next;

      };

      typedef N* node_ptr;

      node_ptr p1;

 

Now suppose further that p1 points to a node of type N in a linked list. Write code that makes p1 point to the next node on the linked list.

 

16.  Suppose you have the following struct definition and typedef statements in your program:

 

                struct N

      {

            double d;

            N* next;

      };

      typedef N* node_ptr;

      node_ptr head, p1, p2;

 

Now suppose further that p1 points to a node of type N in the middle of a linked list (neither the first nor the last node).  Write code that deletes the node after the node p1 points to in the linked list. After the code is executed, the linked list should be the same, excepting the specified node is missing.

 

17. The discipline for a stack is:

                a) data first inserted is the data first out.

                b) for a misbehaving stack, 30 lashes.

                c) data last inserted is the data first out.

                d) depends on the application of the stack.

 

18. Data is removed from a stack in the _____ _______ it was entered.

                a) same order

                b) reverse order

                c) alternating order

                d) sorted order

               

 

19. Name the stack operations as implemented in the text. Tell what each does.

 

20. Give pseudocode for inserting a node in front of the head node in a linked list.

 

 

III.      Part Three

 

1. True/False: In C++, inheritance has to do with the gene pool. Explain.

2. What are the benefits of inheritance and Object Oriented Programming?

3. Given the class below, tell what the default constructor initializes the data member to. Name this initialization technique and give another way to write the constructor.

      class A

      {

      public:

        A();

      private:

        int a;

      };

     

      A::A() : a(17)

      {

        //deliberately empty

      }

4. A base/member initialization list is preceded by

    a) two colons

    b) a dot (or period)

    c) a single colon

    d) a semicolon

5.  A base/member initialization list produces results that are exactly ________

    a) assignment

    b) redeclaration

    c) redefinition

    d) initialization

    e) output

6. The statement int sum(0); performs ____________

    a) a declaration of a function

    b) definition of and intializes an int variable to 0.

    c) redefines sum

    d) overloads sum

7. When a derived class inherits from a base class, how is the base class constructor called?

8. Should members data be initialized in an initializer list? If not always, when should an exception be made?

9. In the code for HourlyEmployee that is derived from Employee, the constructor code appears

   HourlyEmployee::HourlyEmployee(string new_name,   

                          string new_number,

                          string new_wage_rate,

                          double new_hours

                          )

  : Employee(new_name, new_number), wage_rate(new_wage_rate),

                                    hours(new_hours)

Describe the purpose of the items after the : in this constructor.

10. Given the declarations:

   class S

   {

   public:

     S(){}

     void doIt(int& x);

   private:

     int a;

     int b;

   };

   S s;

   int n;

Write a call to the member function doIt with calling object s and argument n.

11. Given the declarations and definitions:

   class S

   {

   public:

     // Assume proper constructors have been defined.

     // The declaration that is part of your answer would go here.

   private:

     int a;

     int b;

   };

Give a declaration (prototype) of a member function, a_plus_b for this class that takes no arguments and returns an int value.

12. Given the declarations and definitions:

   class S

   {

   public:

     // Assume proper constructors have been defined.

     // The declaration that is part of your answer would go here.

   private:

     int a;

     int b;

   };

   // The definition that is part of your answer would go here.

Give a definition of a member function named a_plus_b for this class that returns the sum of the int members a and b of the class S.

13. Consider the following program:

   #include <iostream>

   class base

   {

   public:

     virtual void member() {std::cout << "base class\n";}

   };

 

   class derived : public base

   {

   public:

     void member() {std::cout << "derived class\n";}

   };

   void function( base& x)

   {

       x.member();

   }

   int main()

   {

      base b;

      derived d;

      function(b);

      function(d);

   }

   a) Give the output of this code.

    b) Give the output when the keyword virtual is omitted.

   c) Explain these results.

14. Describe the 'slicing problem' in inheritance.

15. Why can't we assign a base class object to a derived class object?

16. What is the problem assigning with the (legal) assignment of a derived class object to a base class object?

17. What is the meaning of the keyword protected seen in base classes?

18. What is the meaning of the phrase "public inheritance"?

19. Consider the class definition and main function.

    //file 15t14.cc

    #include <iostream>

 

    class A

    {

    public:

        A();

    virtual int f();

    private:

        int a;

    };

    A::A():a(0) { std::cout << "constructor A() called \n";}

    int main()

    {

       A x;

    }

At this point the programmer compiles the class definition and main function. She gets the error message:

g++ 15t14.cc

/tmp/cca237091.o: In function `A::A(void)':

/tmp/cca237091.o(.text+0xa): undefined reference to `A virtual table'

Explain what is wrong.

20. Given the following classes:

    class base

    {

    public:

      void pb();

    protected:

      int b1

    private:

      int b2;

    };

 

    class derived : public base

    {

    public:

        void pd();

    protected:

      int d;

    };

    // assume that all member and friend functions are

    // defined here.

    void outside(){/* . . . */}

    base bb;

    derived dd;

List every member that the function mentioned below can access. Several cases will be the same.

a) function base::pb()

b) function derived::pd()

d) function outside()

 

21. Describe and distinguish function overloading, redefinition of functions and overriding of functions.

 

IV.      Part Four

 

1. Write a program to convert from 24 hour time to 12 hour time.  You may use class DigtalTime from Chapter 8 as a starting point. You will need to replace the terminating error reporting code with calls to the required exception, TimeFormatError.  Provide error messages appropriate to the particular errors as detected.  Then insert the try-catch blocks, terminating the program at the error. After this is tested and debugged  provide the loop to request repetition.  In this example we need to show we understand the three most important features of exceptions: throwing, catching, retrowing and processing.

 

 

 

Answers to Review Problems

 

 

I.  Answers to Part I Problems

 

1.  Templates provide a facility to allow the definition of functions and classes that have parameters for type names. A synonym for templates is ‘generic’ functions and classes.

 

2.  False. The template facility provides for both parameterized types in functions and in classes.

 

3.  False. The template facility provides for both parameterized types in functions and in classes.

 

4. b) classes, and d) functions, where the types of objects in these are deduced from the invocation.

 

5. d. Any type whether a primitive type (provided by C++) or a type defined by the user (a class or struct tag, an enum tag, or a typedef’ed array, or int, float, double etc.)

 

6. True. A function template behaves as a very large collection of overloaded function definitions, but unlike overloadings, where code is generated for each overloading, the template only generates functions when an instantiation is requested.

 

7. a. The following

 

  int x = 14;

  problem_7( x );

 

will create an instance of this function, as though it had been declared

 

    b.  void problem_7 ( int integer_variable );

 

8.  a. the declaration and precondition are:

 

  // precondition: T is a type for which operator< is defined

  // postcondition: function returns the smaller argument

  template<class T>

  T minimum( T left, T right);

 

     b.  the definition is:

 

  template<class T>

  T minimum( T left, T right)

  { 

    if ( left < right )

      return left;

    return right; 

  }

 

    c. The swap function uses operator<. The compiler will produce an error, and refuse to compile the program if a type is used for which operator< is not defined.

 

9. A good general strategy for writing function templates is to write an ordinary (non-template) function first. Then completely debug the ordinary function.  Finally convert the ordinary function to a template function by replacing type names with a type parameter. The concrete case is easier to understand. There are fewer details to worry about, in particular, you do not have to be concerned about template syntax rules.

 

10. There is a rule “Every template argument specified in the template-argument-list must be used in the argument of a function template.” (ARM, page 346.)

 

The g++ compiler complains like this:

 

        g++ 13tstq9.cc

   13tstq9.cc: In function `int main()':

   13tstq9.cc:11: incomplete type unification

   13tstq9.cc:11: incomplete type unification

   13tstq9.cc:11: type unification failed for function template

        void f(int &)'

 

   Compilation exited abnormally with code 1 at Sat Oct 21 23:47:42

 

11. d) there is no restriction on the number of function template type parameters.

 

12. c) Code for template function is generated by the compiler when the call is encountered during the compiling of the C++ program.

 

13. This answer is very local. Possible answers range from ‘no problems’ - I am unaware of template problems with the Borland compilers, except that there are ambiguities are reported that this compiler should resolve.

I have been warned about a few problems in Microsoft compilers (which I have no experience with, and will not attempt to report here, other than to suggest that you read the documentation and test the compiler with your issues.) There are ugly #include directives necessary with g++ to achieve the appearance of separation of implementation and specification.

Some later versions of g++ has pragmas (a sort of compiler directive) that allows some separation of template functions and implementation.

 

14. False: The text’s statement on this is: The member functions for a class template are defined the same way and put in the same location as member functions for ordinary classes. The only difference is that the member functions are themselves templates.

 

15. True

 

16. 

  template<class T>

  void Problem<T>::f( T x)

  {

    // whatever f does

  }

 

17. False. If the template class name is Pair, the class name before the scope resolution operator must be Pair<T>, not just Pair.

 

18. In the constructor instantiation, A::A() is wrong, it must be A<T>::A()

 

19. The constructor A is a template function, hence it requires a template prefix:

  template<class A>

  A<T>::A()

  {

    ...

  }

 

 

20. Mostly true. The only difference is the use of

 

        class_name<type_argument>

 

for the name of the class rather than just class_name.

 

21. The answers are somewhat compiler dependent.

 

General answer: The only failure that my compilers detect is part b. The failure is due to a violation of the requirement that each template type argument be used in the function argument list. The template facility cannot determine the type of the template from the return type alone.

 

Compiler specific error messages:

 

g++  compiles all but part b. Compiling part b. fails upon the attempt to instantiate func(). There is a type unification failure message.

 

Borland 4.0, which is very strict, only complains about b. The message is more informative: "Template function argument 'B' not used in argument types"

 

Aside: If all these templates are placed in a single program, serious ambiguity exists, and not all compilers are smart enough to resolve them.

 

 

 

 

II.  Answers to Part II Problems

 

1. b)

 

2. head->count = 12;

   (*head).count = 12;

 

3. strcpy( head->item, "Wilbur's brother Orville" );

 

4. The value is the NULL or 0 pointer. It is used to signal the end of the linked list.

 

5. Stop Light

   Stop Light

   10

   10

 

6. delete [] head;

 

7. typedef Node* NodePtr;

 

8. b)

 

9. a)

 

10. Even though the instructions say to assume the search has been done, I include it, as it really is necessary.

 

 

 

                Code:

                NodePtr after_me;

      NodePtr temp_ptr;

      after_me = search(head, target);                // 1

      temp_ptr = new Node;                            // 2

      temp_ptr->data = data_to_be_added;

      temp_ptr->link = after_me->link;                // 3

      after_me->link = temp_ptr;                      // 4

 

 

11.

                Code:

                NodePtr discard_me;

      NodePtr temp_ptr;

      discard_me = search( head, discard_data);

      head->link = discard_me->link;

      delete discard_me

 

12. a) Inserting a new item into a large linked list is more efficient than insertion into a large array. If we are inserting into a list, you have about 5 operations, most of which are pointer assignments, regardless of the list size. If you insert into an array, on the average, you have to move about half the array entries to insert a data item.

 

(For small lists, the answer is c) about the same.)

 

13. a) For a large linked list, deletion involves about 3 operations. For a large array, deletion (and the necessary close up of the array) on the average, involves moving about half the array elements.

 

14. the NULL, or the 0 pointer.

 

15. p1 = p1->next;

 

16.           node_ptr delete_me;

                delete_me = p1->next;   // delete_me points to the node to be
                              // deleted

      p1->next = delete_me->next;

                              // node is removed from the list, but
                              // memory has not been deallocated

      delete delete_me;

                              // memory has been recycled

 

17. a) is for a queue, which we haven't studied,  b) is a joke, c) A stack is LIFO, last-in/first-out. and d) is nonsense.

 

18. b) Stack discipline returns data the newest first.

 

19. Push puts the argument on the stack. The pop member function checks for empty stack, if non-empty, then pop removes the top item from the stack and returns it, if the stack is empty, pop terminates the program.  The empty member function returns true if there is nothing on the stack.

 

20.           1) Create a dynamic variable for the node to be inserted, pointed to by temp_ptr:

            temp_ptr = new NodeType;

 

                2) Set the data members of the node

 

                3) make the link field of the new node point to the first node (head node) of the list.

 

        4) make the head pointer point to the new node.

 

 

III.  Answers to Part III Problems

 

1. False. Inheritance has to do with class relationships where one class (the derived class) acquires (inherits) features from another class (the base class) and adds its own features to the inherited features.

2. Abstraction and code reuse: A general form of a class can be defined. It contains common features of the several specialized versions that may be defined and caused to inherit from the general form.

Though the text does not say this, inheritance and OOP enable better modeling of problems within programs.

3. This is a base or member initializer list, albeit a short one. The alternate way to initialize in this constructor follows.

      A::A()

      {

        a = 17;

      }

4. c) a single colon

5. d) initialization.

6. b) int sum(0); defines int variable sum and initializes it to 0.

7. The base class constructor is called in the base initializer list.

8. Data members of a class should be initialized in the initializer list unless argument screening is desired. This you do in the constructor body.

9. The Employee(new_name, new_number) invokes the base class constructor to initialize the data members in the members of HourlyEmployee that are inherited from the base class Employee.

The two items wage_rate(new_wage_rate, hours(new_hours) are initializers for the data members wage_rate and hours in the derived class.

10. s.doIt(n);

11.  int S::a_plus_b();

This prototype may be placed in the class definition in this form, but more usually, the class definition will be thus:

   class S

   {

   public:

     // Assume proper constructors have been defined.

     int a_plus_b();

   private:

     int a;

     int b;

   };

12.

    int S::a_plus_b()

   {

     return a + b;

   }

13.

a)   base class

     derived class

b)   base class

     base class

c) An overridden member function is one that is declared with the keyword virtual in the base class and is declared in the derived class with the same signature as in the base class.

A redefined function is one that is declared in the base class without the virtual keyword, and in the derived class with the same signature. A base class member with the same name as the function in the derived class is hidden by the derived class member.

When an overloaded derived class member function is called through a base class reference or pointer, C++ keeps a table (called the virtual table) that tells what member function to call through the pointer or reference.

When a redefined member is called through a reference or pointer, the member called is that belonging of type of the pointer, not the type of the object pointed to by the pointer.

14. The slicing problem refers to the situation where a variable of type base class is assigned a value of a variable of the derived class.  The only parts of the derived class that are retained in such an assignment is the base class parts of the derived class.

Slicing is an equal opportunity problem in that it affects member functions and data members alike. In particular, slicing occurs regardless of whether the member functions are virtual.

15. There is nothing to assign to the derived class's added members.

16. It is certainly legal to assign a derived class object to a base class object. However, this discards the derived class members that are not members of the base class. This is the "slicing problem."

17. The members declared in a section of a class marked protected are accessible to base class member functions but to no other functions except those in publicly derived classes.

In publicly derived class member functions, these members are accessible exactly as private members of the derived class are accessible.

18. The phrase "public inheritance" refers to the effect of the public access specifier that may occur in the definition of a derived class as follows:

      class base {/*...*/};

      class derived : public  {/* . . . */};

 

This means that the public members of the base class are accessible as if public members of the derived class, protected members of the base class are accessible as if protected members of the derived class. Members of the base class declared private remain private, i.e., inaccessible to any functions other than base class member functions.

19. This is mistake so very easy to make when doing incremental development. The programmer has defined a class with one or more virtual member functions. The compiler will complain about not being able to find the virtual table. The error is not providing a definition for the virtual function in this class.

20.

    a) pb() can call itself and pd(), and can access b1, b2, and d

    b) pd() can call itself, pb(), and can access b1 and d

    c) outside() can call itself and public members of the base and of the derived class.

21. Functions may be overloaded inside classes with or without inheritance, but overloaded functions have different signatures and are defined in the same scope (either in the same class or defined as global functions. (Functions defined in the same namespace also may be overloaded, but we have not dealt with namespaces sufficiently to expect students to give this part of the answer.)

Functions may redefined only as members of classes. If a function member appears in a base class without the virtual keyword and this member function appears with the same signature in a derived class, the derived class member function redefines the base class member implementation. This situation is also described as 'hiding'. If such a member is called through a pointer the function member called follows the type of the pointer.

Functions are overridden in exactly the situation described for redefinition except that the base class function is declared with the virtual keyword. The result is that when the member is called through a reference or a pointer, the function called follows the object assigned, not the pointer type.

 

IV.  Answers to Part IV Problems

 

1.

// dtime.h

// Taken from Chapter 8

//

// This is the HEADER FILE dtime.h. This is a reduction of the

// INTERFACE for the class DigitalTime from Chapter 8 for Chapter 16.

// The operator == and Advance members are not

// needed so we deleted them.  In addition, we have added the required

// exception  class TimeFormatMistake.

//

// Values of this type are times of day. The values are input and

// output in 24 hour notation as in 9:30 for 9:30 AM and 14:45 for

// 2:45 PM.

 

#ifndef DTIME_H

#define DTIME_H

#include <string>

#include <iostream>

 

using namespace std;

class TimeFormatMistake

{

 public:

  TimeFormatMistake(std::string mesg) throw ()

{    message = mesg;    }

 

 

  string what() throw()

  {

    return message;

  }

 private:

  std::string message;

};

 

 

class DigitalTime

{

public:

 

    DigitalTime(int the_hour, int the_minute) throw(TimeFormatMistake);

    //Precondition: 0 <= the_hour <= 23 and 0 <= the_minute <= 59.

    //Initializes the time value to the_hour and the_minute.

 

    DigitalTime( ) throw ();

    //Initializes the time value to 0:00 (which is midnight).

 

   

 

    void TwelveHourTime();

    // returns the time in 12 hour format: hh:mm AM or hh:mm PM

 

    friend std::istream&

    operator >>(std::istream& ins,

                DigitalTime& the_object) throw(TimeFormatMistake);

    //Overloads the >> operator for input values of type DigitalTime.

    //Precondition: If ins is a file input stream, then ins has

    //already been connected to a file.

 

    friend std::ostream&

    operator <<(std::ostream& outs,

                const DigitalTime& the_object);

    //Overloads the << operator for output values of type DigitalTime.

    //Precondition: If outs is a file output stream, then outs has

    //already been connected to a file.

  

    void Print12HourTime() throw();

 

private:

    int hour;

    int minute;

};

 

 

#endif //DTIME_H

 

// file: dtime.cpp

// Adapted from Chapter 8.

//

//This is the IMPLEMENTATION FILE for Programming Problem #1.  The

//original dtime.cxx has been modified to add throw declarations,

//replace error message reporting and exit code with exception throw

//statements.

 

//We have removed definitions of members not used in this problem.

//The interface for the class DigitalTime is in the header file

//dtime.h.

 

#include <iostream>

#include <cctype>

#include <cstdlib>

#include "dtime.h"

 

using namespace std;

 

//These PROTOTYPES are for the definition of the overloaded

//input operator >>:

 

void read_hour(istream& ins, int& the_hour) throw (TimeFormatMistake);

//Precondition: Next input in the stream ins is a time in notation,

//              like 9:45 or 14:45.

//Postcondition: the_hour has been set to the hour part of the time.

//               The colon has been discarded and the next input to

//               be read is the minute.

 

void read_minute(istream& ins, int& the_minute);

//Reads the minute from the stream ins after read_hour has read the hour.

 

int digit_to_int(char c) throw (TimeFormatMistake)

//Precondition: c is one of the digits '0' through '9'.

//              Returns the integer for the digit; e.g.,

//              digit_to_int('3') returns 3.

{

  if ( '0' <= c && c <= '9')

    return c - '0';

  throw TimeFormatMistake("non digit arg for digit_to_int");

  //  return 0;

  // ANSI requires a return statement, even if inaccessible.

}

 

//Uses iostream, cstdlib and stdexcept:

DigitalTime::DigitalTime(int the_hour,

                         int the_minute) throw (TimeFormatMistake)

{

  if (the_hour < 0 || the_hour > 23 ||

      the_minute < 0 || the_minute > 59)

    throw TimeFormatMistake

                   ("Illegal argument to DigitalTime constructor.");

    else

    {

        hour = the_hour;

        minute = the_minute;

    }

}

 

DigitalTime::DigitalTime( ) throw()

{

    hour = 0;

    minute = 0;

}

 

 

void DigitalTime::Print12HourTime() throw()

{

  enum {AM, PM} am_pm = PM;

  int h, m;

 

  if (hour < 12) am_pm = AM;

 

  if (hour == 0 || hour == 12)

    h = 12;

  else if(hour < 12)

    h = hour;

  else

    h = hour - 12;

 

  cout << h << ":" ;

 

  if (0 <= minute && minute < 10) cout << 0 << minute;

  else cout << minute;

 

  if(am_pm == AM) cout << " AM";

  else cout << " PM";

}

 

//Uses iostream:

istream& operator >>(istream& ins, DigitalTime& the_object)

                                          throw (TimeFormatMistake)

{

    read_hour(ins, the_object.hour);

    read_minute(ins, the_object.minute);

    return ins;

}

 

//Uses iostream:

ostream& operator <<(ostream& outs, const DigitalTime& the_object)

{

    outs << the_object.hour << ':';

    if (the_object.minute < 10)

        outs << '0';

    outs << the_object.minute;

    return outs;

}

 

//Uses iostream, cctype, cstdlib, and stdexcept:

void read_hour(istream& ins, int& the_hour) throw(TimeFormatMistake)

{

  char c1, c2;

  ins >> c1 >> c2;

 

  if (!( isdigit(c1) && (isdigit(c2) || c2 == ':')))

    throw TimeFormatMistake

                 ("Non-digit input to read_hour or bad separator\n");

 

  if (isdigit(c1) && c2 == ':')

  {

    the_hour = digit_to_int(c1);

  }

  else //(isdigit(c1) && isdigit(c2))

  {

    the_hour = digit_to_int(c1)*10 + digit_to_int(c2);

    ins >> c2; //discard ':'

 

    if (c2 != ':')

      throw TimeFormatMistake

                       ("Error illegal separating character\n");

  }

 

  if ( the_hour < 0 || the_hour > 23 )

    throw TimeFormatMistake

               ("Error illegal range for input to read_hour\n");

 

}

 

//Uses iostream, cctype, stdlib and stdexcept:

void read_minute(istream& ins, int& the_minute)

{

  char c1, c2;

  ins >> c1 >> c2;

 

  if (!(isdigit(c1) && isdigit(c2)))

    throw TimeFormatMistake("Non-digit input to read_minute\n");

 

  the_minute = digit_to_int(c1)*10 + digit_to_int(c2);

 

  if (the_minute < 0 || the_minute > 59)

    throw TimeFormatMistake

              ("Error illegal range for input to read_minute\n");

}

 

 

// Ch16Prog01.cxx

// driver program for Chapter 16 Programming Problem 1.

//

#include "dtime.h"

 

char getAns()

{

   char c;

   cin.get(c);

   while (c != 'y'&& c != 'n')

   {

     cout << "y/n, please.\n";

     cin.get(c);

   }

   return c;

}

 

int main()

{

   using namespace std;

   DigitalTime time24;

   char stuff[1002];

   char ans;

 

   while( true )

   {

     cout << "Enter time in 24 hour format: hh:mm\n";

     try

     {

       cin >> time24;

       cout << "That is the same time as\n";

       time24.Print12HourTime();

       cout << endl;  

       cout << "Again? (y/n) \n";

       ans = getAns();

       if (ans == 'n') return 0;

     }

     catch (TimeFormatMistake tfm)

     {

       cout << tfm.what() << flush;

       cin.getline(stuff, 1000); // discard all waiting input

     }

   }

   return 0;

}

 

/* Trial Run

machine%> ./a.out

Enter time in 24 hour format: hh:mm

13:07

That is the same time as

1:07 PM

Again? (y/n)

y/n, please.

y

Enter time in 24 hour format: hh:mm

10:15

That is the same time as

10:15 AM

Again? (y/n)

y/n, please.

y

Enter time in 24 hour format: hh:mm

10:65

Error illegal range for input to read_minute

Enter time in 24 hour format: hh:mm

16:05

That is the same time as

4:05 PM

Again? (y/n)

y/n, please.

n

machine %>

*/