csci3081/class-repo-public/Exercises/classDefRobots/classDefExercise.md
Michael Zhang 1ba4536588
f
2018-01-29 17:24:20 -06:00

4.6 KiB

Demonstration of Class Definition in C++


This first example makes use of the default constructor, but this is problematic due to initialization.

Robot.h

class Robot {
private:
  float directionAngle;
  int position[2];

public:
  void moveForward( int distance );
  void display();
};

Robot.cpp

#include "robot.h"
#include <math.h>
#include <iostream>

void Robot::moveForward(int distance) {
  position[0] = position[0] + distance*cos(directionAngle);
  position[1] = position[1] + distance*sin(directionAngle);
}

void Robot::display() {
  cout << "Pos [" << position[0] << " " << position[1] << "]. angle "
  << directionAngle << endl;
}

main.cpp

In C++, main() serves as the entry point to the program. It must exist to generate an executable.

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

using std::cout;

int main() {
  Robot rosyRobot;
  rosyRobot.display();
}

You can compile the program using the provided makefile, then call the executable robot.

make
./robot

We will fix the initialization problem by adding "setters" and add some "getters" while we are at it.

Robot.h

class Robot {
private:
  float directionAngle;
  int position[2];

public:
  // setters and getters
  void position( int x, int y);
  int* position();
  void radianDirectionAngle(float theta);
  float radianDirectionAngle();

  void moveForward( int distance );
  void display();
};

Robot.cpp

Adding the following to the source code.

// setters and getters
void Robot::xyPosition( int x, int y) {
  position[0] = x;
  position[1] = y;
}
int* Robot::xyPosition() {
  return position;
}

void Robot::radianDirectionAngle(float theta) {
  directionAngle = theta;
}
float Robot::radianDirectionAngle() {
  return directionAngle;
}

main.cpp

int main() {
  Robot rosyRobot;
  rosyRobot.xyPosition(0,0);
  rosyRobot.radianDirectionAngle(0);

  rosyRobot.display();
}

This is dangerous to require users to initialize. Let's fix this by forcing the user to provide initialization.

Adding to Robot.h

We can pass along an array, but let's not do that right now. We will see why later.

  Robot( int x, int y, float theta );

Adding to Robot.cpp

Robot( int x, int y, float theta ) {
  position[0] = x;
  position[1] = y;
  directionAngle = theta;
}

This can be cumbersome, let's give the user some options.

OPTION 1: Add a no-parameter constructor that initializes to reasonable values.


Adding to robot.h

public:
  Robot();

Adding to robot.cpp

Robot::Robot() {
  position[0] = 0;
  position[1] = 0;
  directionAngle = 0;
}

Change main.cpp

int main() {
  Robot rosyRobot;
  rosyRobot.display();
}

OPTION 2: Add a constructor with a subset of the member variables.

Adding to robot.h

public:
  Robot();
  Robot( int x, int y );
  Robot(float theta);

Then you will add these definitions to robot.cpp. Let's see how we use them.

main.cpp

int main() {
  Robot rosyRobot;
  Robot c3poRobot(100,100);
  Robot halRobot(0,0,3.14/2);
  Robot eveRobot(-100,-100,-3.14/4);
  rosyRobot.display();
  c3poRobot.display();
  halRobot.display();
  eveRobot.display();
}

Looks like this when you run it ...

Pos [0 0]. angle 0
Pos [100 100]. angle 0
Pos [0 0]. angle 1.57
Pos [-100 -100]. angle -0.785

OPTION 3: (Probably the best) Create a single constructor that can take 1 to all member variable initializations.

Now we have to undo some of our work. We need only the one constructor, because we will add default values.

robot.h

  Robot( int x=0, int y=0, float theta=0);

robot.cpp

Robot::Robot( int x, int y, float theta ) {
  position[0] = x;
  position[1] = y;
  directionAngle = theta;
}

main.cpp

There was no need to change anything in main from before. All of the various forms of constructors was captured in the one constructor with default arguments.

int main() {
  Robot rosyRobot;
  Robot c3poRobot(100,100);
  Robot halRobot(3.14);
  Robot eveRobot(-100,-100,-3.14/4);
  rosyRobot.display();
  c3poRobot.display();
  halRobot.display();
  eveRobot.display();
}

And it comes out like this ...

Pos [0 0]. angle 0
Pos [100 100]. angle 0
Pos [3 0]. angle 0
Pos [-100 -100]. angle -0.785

OOPS. What happened to hal? We specified an angle of 3.14, but that didn't work. Can you explain that?


#### Position is awkward and prone to error. Let's fix that with a class definition.
struct Position {
  int x;
  int y;
};

But now we have to change all of our code. Too bad we didn't think about this change before we started!