NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · December 2016

Question 6 of 9: Object-Oriented Design — A Templated Vector Class

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format. 98-Comp-A4 Program Design and Data Structures, December 2016 — 3 hours, closed book, no calculator permitted. Nine questions of equal weight (20 marks each: 1, 2 and 9 split as (a) 10 + (b) 10); candidates answer any six, so a complete paper is 120 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written (or corrected where the printed paper itself has a slip), but a clear, correctly reasoned pseudocode answer would earn the same marks.

Reference texts for this subject.

  • Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, 4th ed. — tree traversals and BSTs (ch. 12), sorting (ch. 2, 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — linked lists and queues (ch. 3), binary search trees (ch. 4).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and templates (ch. 9–12), file streams (ch. 14), operator overloading (ch. 11).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/array I/O idioms (ch. 1, 7), pointers, structures and linked lists (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — class templates and value semantics (ch. 3, 25–27).

The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.

Question 6: Object-Oriented Design — A Templated Vector Class (20 marks)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Given. A requirement for a templated fixed-size numeric vector type with element access, arithmetic, equality, and printing, usable for int, float and double.

Find. A Vector.h / Vector.cc pair implementing the class.

Approach. Store the size and a heap-allocated element array; overload operator[] for read/write access (with two overloads, const and non-const, so the class works in both contexts), operator+/operator- for element-wise sum/difference, operator* for the dot product (the only size-preserving, mathematically standard product of two same-length vectors), and operator== for element-wise equality; every binary operator checks sizes first, per the stated requirement.

  1. State the interpretation of "multiplication." Assumption: since the class stores fixed-size 1-D vectors (not matrices), the only multiplication that keeps "same size required" and "result is meaningful" is the inner (dot) product $\sum_i a_i b_i$, which returns a scalar of the element type rather than another Vector. An element-wise (Hadamard) product would also satisfy "same size," but the dot product is what "vector multiplication" conventionally means in engineering contexts, so it is adopted here and stated explicitly as the paper instructs.
  2. Write Vector.h.
    // Vector.h
    #ifndef VECTOR_H
    #define VECTOR_H
    #include <iostream>
    
    template <typename T>
    class Vector {
    public:
        explicit Vector(int size);              // declare, uninitialized elements
        Vector(const Vector& other);
        Vector& operator=(const Vector& other);
        ~Vector();
    
        int size() const { return n; }
        T&       operator[](int i);             // read/write access
        const T& operator[](int i) const;
    
        Vector  operator+(const Vector& rhs) const;
        Vector  operator-(const Vector& rhs) const;
        T       operator*(const Vector& rhs) const;   // dot product (see note)
        bool    operator==(const Vector& rhs) const;
    
        template <typename U>
        friend std::ostream& operator<<(std::ostream& os, const Vector<U>& v);
    
    private:
        int n;
        T*  data;
        void check_same_size(const Vector& rhs, const char* op) const;
    };
    
    #include "Vector.cc"   // template definitions must be visible at instantiation
    #endif
  3. Write Vector.cc.
    // Vector.cc
    #include "Vector.h"
    #include <cstdlib>
    
    template <typename T>
    Vector<T>::Vector(int size) : n(size), data(new T[size]) {}   // uninitialized elements
    
    template <typename T>
    Vector<T>::Vector(const Vector& other) : n(other.n), data(new T[other.n]) {
        for (int i = 0; i < n; i++) data[i] = other.data[i];
    }
    
    template <typename T>
    Vector<T>& Vector<T>::operator=(const Vector& other) {
        if (this == &other) return *this;
        delete[] data;
        n = other.n;
        data = new T[n];
        for (int i = 0; i < n; i++) data[i] = other.data[i];
        return *this;
    }
    
    template <typename T>
    Vector<T>::~Vector() { delete[] data; }
    
    template <typename T>
    void Vector<T>::check_same_size(const Vector& rhs, const char* op) const {
        if (n != rhs.n) {
            std::cerr << "Error: Vector " << op
                       << " requires operands of the same size (" << n
                       << " vs " << rhs.n << ")\n";
            std::exit(1);
        }
    }
    
    template <typename T>
    T& Vector<T>::operator[](int i) { return data[i]; }
    template <typename T>
    const T& Vector<T>::operator[](int i) const { return data[i]; }
    
    template <typename T>
    Vector<T> Vector<T>::operator+(const Vector& rhs) const {
        check_same_size(rhs, "+");
        Vector result(n);
        for (int i = 0; i < n; i++) result[i] = data[i] + rhs.data[i];
        return result;
    }
    
    template <typename T>
    Vector<T> Vector<T>::operator-(const Vector& rhs) const {
        check_same_size(rhs, "-");
        Vector result(n);
        for (int i = 0; i < n; i++) result[i] = data[i] - rhs.data[i];
        return result;
    }
    
    template <typename T>
    T Vector<T>::operator*(const Vector& rhs) const {   // dot product
        check_same_size(rhs, "*");
        T sum = data[0] * rhs.data[0];
        for (int i = 1; i < n; i++) sum = sum + data[i] * rhs.data[i];
        return sum;
    }
    
    template <typename T>
    bool Vector<T>::operator==(const Vector& rhs) const {
        if (n != rhs.n) return false;              // different-size vectors are simply unequal
        for (int i = 0; i < n; i++) if (data[i] != rhs.data[i]) return false;
        return true;
    }
    
    template <typename U>
    std::ostream& operator<<(std::ostream& os, const Vector<U>& v) {
        os << "(";
        for (int i = 0; i < v.n; i++) os << v.data[i] << (i + 1 < v.n ? ", " : "");
        os << ")";
        return os;
    }
    Note the deliberate asymmetry: operator== reports "not equal" for mismatched sizes (a well-defined boolean answer, so no error is raised), while +, - and * raise the error the question asks for, since there is no meaningful result to return.
  4. Confirm on a 3-element example. For Vector<int> a = {1,2,3} and b = {4,5,6}: $a+b=(5,7,9)$, $a-b=(-3,-3,-3)$, and the dot product $a\cdot b=1(4)+2(5)+3(6)=32$. $$\boxed{a+b=(5,7,9),\ \ a-b=(-3,-3,-3),\ \ a\cdot b=32}$$
Question 6 — results
Operation on (1,2,3), (4,5,6)Result
Sum(5, 7, 9)
Difference(−3, −3, −3)
Dot product32
Mismatched-size operationerror message, program aborts the operation