Trying to figure out class inheritance

Hi all,

I am trying to figure out how class inheritance works. I can’t even get the constructor of the inherited class to work.

Here are the current contents of my files:

ClassTest.h

#ifndef ClassTest_h
#define ClassTest_h

class Switch {
  public:
    Switch(byte pin);
    virtual void readPin();
    virtual byte getPinStatus();
  protected:
    byte MYpin;
    byte pinStatus;
};

class Toggle : public Switch {
  public:
    Toggle::Toggle(byte pin);
};

#endif

ClassTest.cpp

#include <Arduino.h>
#include "ClassTest.h"

Switch::Switch(byte pin) {
  pinMode(pin, INPUT_PULLUP);
  MYpin = pin;
}

void Switch::readPin() {
  pinStatus = digitalRead(MYpin);
}

byte Switch::getPinStatus() {
  readPin();
  return pinStatus;
}

 Toggle::Toggle(byte pin) {
  Switch::Switch(pin);
 }

ClassTest.ino:

#include "ClassTest.h"
Toggle btn(2);

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  if(btn.getPinStatus()) digitalWrite(13, LOW);
  else                   digitalWrite(13, HIGH);
}

Where am I wrong?

Thanks for you help.

Jacques

Switch::Switch(byte pin) {
  pinMode(pin, INPUT_PULLUP);
  MYpin = pin;
}

At the time that the constructor is called, the hardware is NOT ready to be diddled with. At least, you should NOT assume that it is.

void Switch::readPin()

Functions with read in the name should return a value!

 Toggle::Toggle(byte pin) {
  Switch::Switch(pin);
 }

You should never call the constructor directly. The proper way to get the base class created is:

Toggle::Toggle(byte pin) : Switch(pin)

Hi Paul,

Functions with read in the name should return a value!

Changed it to :

updatePin();

In ClassTest.h:

Toggle(byte pin): Switch(pin) {};

Seems to work. I removed

Toggle::Toggle(byte pin) {
  Switch::Switch(pin);
 }

from ClassTest.cpp

At the time that the constructor is called, the hardware is NOT ready to be diddled with. At least, you should NOT assume that it is.

At which point can I assume that the hardware is ready? setup()?
I saw pinMode() called in constructors in other classes made by other people and I thought it was a good idea.

Thanks for your help.

Jacques

I solved the problem.

I removed pinMode() from the constructor and added the following line to updatePin():

if (firstPass) { pinMode(MYpin, MYmode); firstPass = false; }

firstPass is initialized as true.

I can do that, because all subclasses need to call updatePin(). It holds the debounce routine.

Thanks again for the warning.

Jacques

You need to be a member of the Aristocracy to figure that out. I'm not. :slight_smile:

...R

The normal way to go would be to create a begin() function that is called in setup.

Whandall:
The normal way to go would be to create a begin() function that is called in setup.

agreed, cuz it tells you that there is a hardware dependancy....

jbellavance:
I removed pinMode() from the constructor and added the following line to updatePin():

So, it gets called every time you do a read/update?

I usually add a separate setup() method to these kinds of classes. Check the link in my setup for a bit of a walkthrough.

So, it gets called every time you do a read/update?

No. It only gets called the first time, on the firstPass through the function.

Adding a setup() or begin() method is a better choice, IMHO.

Then maybe I sould just forget about initialising pinMode and let the user do it him/herself. pinMode is called in the setup section anyways.

I don't see myself writing a method called pinMode() to set pinMode().

I don't see myself writing a method called pinMode() to set pinMode().

Good. Call the method begin(), like all the other classes that have post-constructor actions to perform.

jbellavance:
I don't see myself writing a method called pinMode() to set pinMode().

I think you are missing the point.

Since you cannot be guaranteed that the class constructor will be called before init() is completed, you want to have a class member function to call during setup() that does the pinMode() work.

If you look at the Servo library, you will see a method called attach() which utilizes that paradigm.

uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure

It is customary to call that class member function in setup() where you are guaranteed that the hardware is ready.

Any arduino class/library that you may have seen that does the hardware work in the constructor may be prone to errors. That is to say for constructors that are creating global objects.

Another very common way to do it would be using pointers, where you can then use the constructor to do the hardware work:

class Blinky{
  public:
    Blinky(int pin){pinMode(pin, OUTPUT);};
    void someMethod(){};
};

Blinky* myObject;  // a pointer to a Blinky object

const byte blinkyPin = 6;

void setup() 
{
  myObject = new Blinky(blinkyPin);  // call constructor using the new keyword, you are guaranteed that the hardware is ready here
  myObject->someMethod(); // notice you have to use the object dereference operator to call the member function
}

void loop() {
  // put your main code here, to run repeatedly:

}

I like the begin() idea. At least, the user does not have to mention a second time the pin number and if his/her setup is with a pullup or a pulldown resistor.