Class 4: C++ Part II

Contents

Explicit type conversion ("casting")

Syntax in C or C++: ( typename ) expr

Alternate C++ syntax: typename ( expr )

Numeric types are also converted implicitly when needed, particularly when it's a "promotion":

Implicit type conversion Explicit type conversion
int i=5;
double x;
x= i;
double x=3.1415;
int i;
i= (int)x;  // C style
i= int(x);  // C++ style

Usefulness of arrays and references:

Suppose in our bouncing ball program we had more than one ball to track.

An algorithm for DrawAllBalls()

Algorithm goal:
Print a line showing where balls are.

Algorithm outline:

Many things demonstrated by DrawAllBalls()

Implementation:

// Print a line showing where balls are:
//  at each position, check whether a ball is there,
//  and print a '*' or ' ' depending
void DrawAllBalls( vector<double> & x, vector<double> & v, int n)
{
  int icolumn; // column index
  int iball;   // ball index
  char c;      // character
  for (icolumn=0; icolumn<80; icolumn++) {
    c= ' ';  // space in this column, unless we find a ball
    // start of ball-search
    for (iball=0; iball<n; iball++) {
      if ( (int)(x[iball]) == icolumn ) {
        c='*';  // found a ball
        break;  // early exit from ball-search loop
      }
    }
    // end of ball-search
    cout << c;  // print ' ' or '*'
  }
  cout << '\n';
}

A more CPU-efficient algorithm

The previous algorithm had two nested loops: one over 80 columns, the other over n balls. The ball position check is done as many as 80*n times. Can we be more efficient? Yes, we can.

Algorithm outline:

Now have only nball loop iterations, not 80*nball.

New DrawAllBalls() algorithm implementation

// Print a line showing where balls are
void DrawAllBalls(vector<double>& x, vector<double>& v, int n)
{
  string s;
  s.resize(80,' ');      // set to 80 spaces
  int iball;             // ball index
  for (iball=0; iball<n; iball++) {  // start of ball loop
      int ix= (int)(x[iball]);
      s[ix] = '*';
  }
  // end of ball loop
  cout << s << '\n';
}

Moral of the story

Sometimes you can find a more efficient algorithm in terms of CPU by doing something a little different. Often this involves using just a little more memory.

Structs: motivation

Suppose our bouncing balls had more parameters: two dimensions, radius, color, name of video game character, etc. Then the main loop might look like this:

while(1) {
  for (int i=0; i<n; i++) {
    MoveBall(x[i],y[i],u[i],v[i],r[i],color[i],name[i],dt);
  }
  DrawAllBalls(x,y,u,v,r,color,name);
}

It would be nice if it could look like this:

while(1) {
  for (int i=0; i<n; i++) {
    MoveBall( balls[i], dt );
  }
  DrawAllBalls( balls );
}

Structs in C/C++

C and C++ let us define our own structures which collect data, possibly of different types, in contiguous memory locations.

Declaration Syntax Memory allocation
struct MyBall_s {
  double x;
  double y;
  double u;
  double v;
  double r;
  int color;
  char symbol;
};

struct MyBall_s ball;
Relative address   contents
0 through 7        x
8 through 15       y
16 through 23      u
24 through 31      v
32 through 39      r
40 through 43      color
44                 symbol

Total size: 45 bytes

Example usage

void MoveBall( struct MyBall_s & ball, double dt )
{
  ball.x= ball.u * dt;
  ball.y= ball.v * dt;
  Bounce(ball.x, ball.u);
  Bounce(ball.x, ball.v);
}

void Bounce( double &x, double &v ) {
{
  // bounce on wall at 79 or 0.
  // Warning: explicit 79 is bad practice!
  if ( (x>=79.0 && v>0) || (x<=0.0 && v<0) )
    v= -v;
}

Exercise (after break)

Modify bouncing ball to have

Class: further define specification, write algorithm. Instructor: code it, with class catching errors.

Some good programming practices

Assignment