Search code examples
c++pointersref

Pass a Pointer or Ref to the constructor of an object


Fairly new to C++ and having an issue with ref vs. pointer. The code below is a class for a simple motor and works. I would like to pass the pin expander in the constructor, but cannot seem to get that working.

I call the methods with &expander. I tried adding a setter and getter for the expander but that did not seem to work.

Is this the best way, and can I pass it to the constructor?

This is the header

#ifndef PMotor_H
#define PMotor_H

#include <Arduino.h>
#include <PCF8575.h>

class PMotor {
private:

  uint8_t pinA;
  uint8_t pinB;
  uint8_t direction;


public:
  // Constructor
  PMotor(uint8_t pinA, uint8_t pinB);

  // Turn the motor on with a specified speed.
  void on(uint8_t direction, PCF8575 *expander);

  // Turn the motor on with a specified speed, for a given time.
  void on(uint8_t direction, int millisec, PCF8575 *expander);

  // Turn the motor off.
  void off(PCF8575 *expander);
  bool movingCW();
  bool movingCCW();


};

#endif

This is the CPP

#include "PMotor.h"
#include <PCF8575.h>

bool mCW;
bool mCCW;

PMotor::PMotor(uint8_t pinA, uint8_t pinB) {
  this->pinA = pinA;
  this->pinB = pinB;
}



void PMotor::on(uint8_t direction, PCF8575 *expander) {

  if (direction == 0) {
    expander->write(pinA, HIGH);
    expander->write(pinB, LOW);
    mCW = true;
    mCCW = false;

  } else {
    expander->write(pinA, LOW);
    expander->write(pinB, HIGH);
    mCW = false;
    mCCW = true;
  }
}

void PMotor::on(uint8_t direction, int millisec, PCF8575 *expander) {
  this->on(direction, expander);
  delay(millisec);
  this->off(expander);
}

void PMotor::off(PCF8575 *expander) {
  expander->write(this->pinA, LOW);
  expander->write(this->pinB, LOW);
  mCW = false;
  mCCW = true;
}

bool PMotor::movingCW() {
  return mCW;
}

bool PMotor::movingCCW() {
  return mCCW;
}

Solution

  • I would like to pass the pin expander in the constructor, but cannot seem to get that working.

    Here's one way that involves taking the expander by reference but storing a pointer. Taking it by reference makes sure that you don't get a nullptr - and storing it as a pointer makes it easy to add copy/move semantics to your class.

    class PMotor {
    private:
        PCF8575* expander; // store a pointer
        uint8_t pinA;
        uint8_t pinB;
        uint8_t direction;
    
    public:
        // Constructor - takes an expander by reference:
        PMotor(PCF8575& expander, uint8_t pinA, uint8_t pinB);
    
        // No expander needed in the rest:
    
        // Turn the motor on with a specified speed.
        void on(uint8_t direction);
    
        // Turn the motor on with a specified speed, for a given time.
        void on(uint8_t direction, int millisec);
    
        // Turn the motor off.
        void off();
    
        bool movingCW();
        bool movingCCW();
    };
    

    Then the implementation of the member functions can look pretty much like they already do - only with the PCF8575* argument removed.

    The constructor would simply be:

    PMotor::PMotor(PCF8575& expander, uint8_t pinA, uint8_t pinB) :
        expander(&expander), // store the pointer
        pinA(pinA),
        pinB(pinB)
    {}
    

    If you would also like to have a setter and getter for the expander, it could look like this:

    class PMotor {
    public:
        // ...
    
        // setter, sets a new expander and returns a reference to the old one
        PCF8575& Expander(PCF8575& new_expander) {
            PCF8575* old_expander = expander;
            expander = &new_expander;
            return *old_expander;
        }
    
        // getters for the expander
        PCF8575& Expander() { return *expander; }
        const PCF8575& Expander() const { return *expander; }
    
        // ...
    };