CSCI 3510
Spring 2004
Solutions to the practice questions for quiz 2

  1. Which of the following are part of an abstract data type specification? (Correct answers are in bold blue.)

    1. A type.
    2. Prototypes for functions in the abstract data type.
    3. A description of how the type is represented.
    4. Implementations of the functions.
    5. Conceptual meanings of the functions.

  2. Object-oriented programming in C++ can be used to make it impossible to violate the abstraction of an abstract data type.

    1. What feature of C++ makes this possible?

      The class, and private members of classes.

    2. Programmers rarely deliberately sabotage their own work. Since programmers are not supposed to violate abstractions, why is it so important that a compiler prevent them from doing so? Can't programmers police themselves?

      Even good programmers make mistakes, and the compiler should catch those mistakes wherever possible.

      Programming teams often have some less experienced programmers who are likely to violate abstractions if permitted to do so. A compiler that disallows such violations gives the better programmers confidence that the less experienced programmers are not violating abstractions.

  3. Suppose that the following structure definition is given.

       struct Widget
       {
         int side;
         char bottom[22];
         Widget(int s, char b[])
         {
           side = s;
           strcpy(bottom, b);
         }
       };
    
    1. Show how to create a new widget called frodo with side = 4 and bottom = "blue". Use the constructor.

          Widget frodo(4, "blue");
          

    2. Suppose that the constructor were not provided as part of the Widget structure type. Show how to create the same widget frodo without using the constructor.

          Widget frodo;
          frodo.side = 4;
          strcpy(frodo.bottom, "blue");
          

  4. When doing object-oriented programming, you typically find that functions have one less parameter than do corresponding functions that are used in procedural (non-object-oriented) computing. For example, a classical function to test whether a value x is present in a table t has two parameters, x and t, but an object-oriented function has only one parameter, x. Explain why there is one less parameter.

    In object-oriented programming, each function is part of an object. The function can refer to the object in which it resides implicitly, so that object is not an explicit parameter. It is an implicit parameter.

  5. A rational number can be represented by a pair of integers, the numerator and the denominator. For example, the rational number with numerator 1 and denominator 3 stands for 1/3. The advantage is that some numbers that can only be represented approximately using type double can be represented exactly as ratios of integers.

    An abstract data type Rational is intended to represent rational numbers. So a member of type Rational is thought of as having a numerator and a denominator. Among the operations are a constructor that takes two integers (a numerator and a denominator) and initializes a rational number; an operation flip so that x.flip() makes x into its reciprocal; an operation multiplyBy so that x.multiplyBy(y) makes x into the product of x's current value and y, where y is a rational number; an operation getNumerator that returns the numerator, and an operation getDenominator that returns the denominator. (So x.getNumerator() is the numerator of x.)

    Rational numbers are always stored in a form where the numerator and denominator have no common factors. Instead of 3/6, you store 1/2. You cannot assume that somebody who uses this data type knows this convention. There is nothing wrong with creating a rational number with numerator 3 and denominator 6. But if you then ask for the numerator, it will be 1, not 3. This can be achieved by dividing the numerator and denominator by their greatest common divisor. Assume that function gcd(m,n) is available to you. You do not need to write it.

    1. Write Rational in C++ as a class, including the constructor and methods flip, multiplyBy, getNumerator and getDenominator. Also provide a private method called reduce that reduces a rational number by dividing the numerator and denominator by their greatest common divisor. You will want to use reduce in some other functions.

        class Rational
        {
          public:
            Rational(int num, int denom);
            int getNumerator() const;
            int getDenominator() const;
            void flip();
            void multiplyBy(const Rational& y);
      
          private:
            int numerator, denominator;
            void reduce();
        };
      
        Rational::Rational(int num, int denom)
        {
          numerator   = num;
          denominator = denom;
          reduce();
        }
      
        int Rational::getNumerator() const
        {
          return numerator;
        }
      
        int Rational::getDenominator() const
        {
          return denominator;
        }
      
        void Rational::flip()
        {
          int holdnum = numerator;
          numerator   = denominator;
          denominator = holdnum;
        }
      
        void Rational::multiplyBy(const Rational& y)
        {
          numerator   = numerator * y.numerator;
          denominator = denominator * y.denominator;
          reduce();
        }
      
        void Rational::reduce()
        {
          int g = gcd(numerator, denominator);
          numerator   = numerator/g;
          denominator = denominator/g;
        }
      

    2. Write a main program that creates rational numbers 1/3 and 3/7, calculates the product of those two numbers, and prints the product in the form numerator/denominator. (So it will print "1/7".)

      Note: This solution uses printf to print. You can also use cout and << to do the job.

        int main()
        {
          Rational r1(1,3);
          Rational r2(3,7);
          r1.multiplyBy(r2);
          printf("%d/%d", r1.getNumerator(), r1.getDenominator());
          return 0;
        }