steveo
steveo

Reputation: 51

Access parameter from function in behaviour class - polymorphism

I'm creating a program that will simulate a race between various runners, using behavior classes to implement different types of runner movements.

To do this, an abstract MoveBehaviour class will be implemented, along with several other concrete sub-classes (etc. WalkBehaviour, SleepBehaviour, SlideBehaviour).

The abstract MoveBehaviour class will require a pure virtual move() function, and the appropriate behaviour will be implemented in the concrete sub-classes. This move() function computes a new position newPos for the runner, given its current position oldPos, and the move() function will return a short, text description of the move in the log parameter (Etc. "walk forward 1 step") , which will be printed to the screen in a later step. I feel as if I'm not returning my log values in these functions correctly, and this relates to another issue.

In the update() function in Runner.cc, I'm supposed to randomly select the runner’s next move behaviour. This involves a new walking behaviour 40% of the time, a sleeping behaviour 40% of the time, and a slide behaviour 20% of the time. I'm supposed to use the new behaviour object to compute a new position that will be stored in the newPos parameter, and then I am to document the move in the runner’s current log data member. Etc if the runner is named Timmy, and the new move behaviour is walking, the current log data member will store the string “Timmy walked one step.”

Going back to my log, I wasn't sure how I would access the string that I declared in each of the move functions for every behaviour class. I noticed there is a getLog() function in Runner.cc, but I feel like it doesn't make sense to use that. This makes me thing I wasn't supposed to declare the "walked one step" strings and such in the move classes but rather in the update classes instead.

Additionally, I don't understand how to get the new behaviour object to compute a new position that will be stored in the newPos parameter and would appreciate some help with that as well.

For getting the log values, I'm just printing the runner's name below and my attempt was going to append whatever was in the log value to this sentence, but I wasn't sure how to access the log values.

I can include the SleepBehaviour and SlideBehaviour classes if needed, but they are practically identical to WalkBehaviour and I figured only one example was needed.

Runner.cc

void Runner::update(Position& newPos){
    int r;
    r = random(100) + 1;
    if(r <= 40){ 
        WalkBehaviour* walk = new WalkBehaviour;
    }else if (r <= 40){
        SleepBehaviour sleep = new SleepBehaviour;
    }else{
        SlideBehaviour* slide = new SlideBehaviour;
    }
    cout << name << endl;
    
}

Position.cc

#include <iostream>
using namespace std;
#include <string>
#include "Position.h"

Position::Position(int i1, int i2) : row(i1), column(i2){ 
}
Position::getRow(){ return row; }
Position::getColumn(){ return column; }
void Position::setRow(int r){ row = r; }
void Position::setColumn(int c){ column = c; }

MoveBehaviour.h

#ifndef MOVEBEHAVIOUR_H
#define MOVEBEHAVIOUR_H

#include <iostream>
#include "Position.h"
using namespace std;

class MoveBehaviour
{
  public:
    virtual void move(Position&, Position&, string&) = 0;
    virtual ~MoveBehaviour() = default;
};

class WalkBehaviour : public MoveBehaviour{
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~WalkBehaviour();
};

class SleepBehaviour : public MoveBehaviour{
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~SleepBehaviour();
};

class SlideBehaviour : public MoveBehaviour{
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~SlideBehaviour();
};

WalkBehaviour.cc

#include <iostream>
using namespace std;
#include <string>
#include "MoveBehaviour.h"

void WalkBehaviour::move(Position& oldPos, Position& newPos, string& log) { 
    newPos.setColumn(oldPos.getColumn() + 1);
    newPos.setRow(oldPos.getRow());
    log = (" walked one step \n");
} 

WalkBehaviour::~WalkBehaviour(){}

Upvotes: 0

Views: 41

Answers (2)

Botje
Botje

Reputation: 31080

First, you need to actually use polymorphism by declaring a pointer to a base MoveBehaviour object that you let point to a derived instance. Additionally, you need to make sure that you don't leak memory, so I chose std::unique_ptr which is automatically freed upon function exit.

Next, you can simply pass an empty std::string for the function to assign the log to, and use a std::stringstream to construct a line with the name with the move description. The output of this stringstream is then added to the log member in one go.

void Runner::update(Position& newPos) {
    int r;
    r = random(100) + 1;
    std::unique_ptr<MoveBehaviour> movement;
    if(r <= 40) { 
        movement = make_unique<WalkBehaviour>();
    } else if (r <= 80) {
        movement = make_unique<SleepBehaviour>();
    } else {
        movement = make_unique<SlideBehaviour>();
    }

    std::string moveLog;
    movement->move(currPos, newPos, moveLog);
    currPos = newPos;
   
    std::stringstream ss;
    ss << name << " " << moveLog << std::endl;
    log += ss.str();
}

Upvotes: 2

Vlad Feinstein
Vlad Feinstein

Reputation: 11321

Here:

if(r <= 40){ 
    WalkBehaviour* walk = new WalkBehaviour;
}else if (r <= 40){
    SleepBehaviour sleep = new SleepBehaviour;
}else{
    SlideBehaviour* slide = new SlideBehaviour;
}

you are creating new behaviors and immediately leaking them. You should have assign them ti Runner's MoveBehaviour* behaviour;, deleting its old behavior first:

delete behaviour;
if(r <= 40){ 
    behaviour = new WalkBehaviour;
}else if (r <= 40){
    behaviour = new SleepBehaviour;
}else{
    behaviour = new SlideBehaviour;
}

Your WalkBehaviour::move() uses log correctly (except that you don't need to enclose text literal into ()

Upvotes: 2

Related Questions