teaching machines

CS 330 Lecture 29 – Virtuality in C++ and Overloading Builtin Operators

April 15, 2013 by . Filed under cs330, lectures, spring 2013.

Agenda

Pulse

Student evaluations are just numbers, but I like to hear anecdotes too. Please take a moment to think about how this course is run: grading scale, homework setup, topics, and so on. Now, suppose you’re teaching a classroom full of up-and-coming computer scientists.

  1. What would you retain?
  2. What would you do differently?

Opportunity

Program This


Rewrite the following using C++ references:

template<typename T> void swap(T *a, T *b) {
  T tmp = *a;
  *a = *b;
  *b = tmp;
}

Code

Functions.h

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

class Function {
  public:
    virtual double evaluateAt(double x) const = 0;
};;;;

class SineFunction : public Function {
  public:
    double evaluateAt(double x) const;
};

class Polynomial : public Function {
  public:
    Polynomial(int degree);
    double evaluateAt(double x) const;
    int GetDegree() const;

    void setCoefficient(int i, double coefficient);

    virtual double *getRoots() const;

  private:
    int degree;

  protected:
    double *coefficients;
};

class LinearFunction : public Polynomial {
  public:
    LinearFunction(double slope, double y_intercept);
    double *getRoots() const;
};

class QuadraticFunction : public Polynomial {
  public:
    QuadraticFunction(double a, double b, double c);
    double *getRoots() const;
};

#endif

Functions.cpp

#include <cmath>
#include <iostream>

#include "Functions.h"

Polynomial::Polynomial(int degree) :
  degree(degree) {
  coefficients = new double[degree + 1];
}

int Polynomial::GetDegree() const {
  return degree;  
}

double Polynomial::evaluateAt(double x) const {
  double sum = 0.0;  
  double xpow = 1.0;
  for (int i = 0; i <= degree; ++i) {
    sum += xpow * coefficients[i];
    xpow *= x;
  }
  return sum;
}

void Polynomial::setCoefficient(int i, double coefficient) {
  coefficients[i] = coefficient;  
}

double *Polynomial::getRoots() const {
  std::cerr << "I don't know how to do that." << std::endl;
  return NULL;
}

LinearFunction::LinearFunction(double slope,
                               double y_intercept) :
  Polynomial(1) {
  setCoefficient(0, y_intercept);
  setCoefficient(1, slope);
}

QuadraticFunction::QuadraticFunction(double a,
                                     double b,
                                     double c) :
  Polynomial(2) {
  setCoefficient(0, c);
  setCoefficient(1, b);
  setCoefficient(2, a);
}

double *LinearFunction::getRoots() const {
  double *roots = new double[1];
  roots[0] = -coefficients[0] / coefficients[1];  
  return roots;
}

double *QuadraticFunction::getRoots() const {
  double *roots = new double[2];
  roots[0] = (-coefficients[1] + sqrt(coefficients[1] * coefficients[1] - 4.0 * coefficients[2] * coefficients[0])) / 2.0 * coefficients[2];
  roots[1] = (-coefficients[1] - sqrt(coefficients[1] * coefficients[1] - 4.0 * coefficients[2] * coefficients[0])) / 2.0 * coefficients[2];
  return roots;
}

double SineFunction::evaluateAt(double x) const {
  return sin(x);  
}

/* ------------------------------------------------------------------------- */

graph.cpp

#include <iostream>
#include "Functions.h"

/* ------------------------------------------------------------------------- */

void draw(const Function &f);

int main(int argc, char **argv) {
  LinearFunction f(1.0, 0.0);
  QuadraticFunction xsquared(1.0, 0.0, -1.0);
  Polynomial p(3);
  p.setCoefficient(0, 0.0);
  p.setCoefficient(1, 0.0);
  p.setCoefficient(2, 0.0);
  p.setCoefficient(3, 1.0);
  draw(SineFunction());
  return 0;
}

/* ------------------------------------------------------------------------- */

void draw(const Function &f) {
  const int NROWS = 21;
  const int NCOLS = 51;

  char plot[NROWS][NCOLS];

  for (int r = 0; r < NROWS; ++r) {
    for (int c = 0; c < NCOLS; ++c) {
      plot[r][c] = ' ';
    }
  }

  for (int c = 0; c < NCOLS; ++c) {
    plot[NROWS / 2][c] = '-';
  }

  for (int r = 0; r < NROWS; ++r) {
    plot[r][NCOLS / 2] = '|';
  }

  plot[NROWS / 2][NCOLS / 2] = '+';

  for (int c = 0; c < NCOLS; ++c) {
    double x = c / (NCOLS - 1.0) * 6.0 - 3.0;
    double y = f.evaluateAt(x);
    int r = (int) (y * NROWS * 0.5 + NROWS * 0.5);
    if (r >= 0 && r < NROWS) {
      plot[r][c] = '.';
    }
  }

  for (int r = NROWS - 1; r >= 0; --r) {
    for (int c = 0; c < NCOLS; ++c) {
      std::cout << plot[r][c];
    }
    std::cout << std::endl;
  }
}

/* ------------------------------------------------------------------------- */

makefile

Note to copy and pasters: makefile rules need to be indented with real tabs, not spaces.

all: graph

Functions.cpp: Functions.h

Functions.o: Functions.cpp
  g++ -c Functions.cpp

graph: graph.cpp Functions.o Functions.h
  g++ -o graph graph.cpp Functions.o

run: run_graph
run_graph:
  ./graph

clean:
  rm -f *.o

roots.cpp

#include <iostream>

#include "Functions.h"

void printRoots(const Polynomial &p) {
  double *roots = p.getRoots();
  if (roots != NULL) {
    for (int i = 0; i < p.GetDegree(); ++i) {
      std::cout << "roots[" << i << "]: " << roots[i] << std::endl;
    }
  }
}

int main(int argc, char **argv) {
  Polynomial xcubed(3); 
  xcubed.setCoefficient(0, 0.0);
  xcubed.setCoefficient(1, 0.0);
  xcubed.setCoefficient(2, 0.0);
  xcubed.setCoefficient(3, 1.0);

  printRoots(xcubed);
  printRoots(QuadraticFunction(1.0, 0.0, 0.0));
  printRoots(LinearFunction(1.0, 3.0));

  std::cout << "0.0f * -0.0f: " << 0.0f * -0.0f << std::endl;

  return 0;
}

Haiku

“What makes OOP?”
“Superpolymorphitance.”
Your next interview.