A few programming questions about inheritance

I'm not sure how to do the following inheritance-related stuff so I'm asking experts for help:

  1. I have a buttons class and I want to construct a child class encoder_buttons from it so all types of buttons can be treated equally. The most important method of the buttons class is sense(), which provides the status of the button and updates internal variables. How do I define a sense for the child class so that ONLY the child sense() is called, not the parent sense().

  2. How do I define a child sense() so that both parent and child sense() are called?

My memory of C++ inheritance is fuzzy. I remember the keyword "super" used in Java but how do I use this in C++?

Big thanks!

I'm not sure I fully understand your explanation but, basic inheritance is kinda like this.

class Base{
  public:
    void DoStuff( void ){return;};
    virtual void DoOtherStuff( void ){return;};
};

class Derived : public Base{
  public:
    void DoOtherStuff( void ){return;}; //Override base member
};

//Usage

Derived d_Derived;

d_Derived.DoStuff(); //Access inherited member
d_Derived.DoOtherStuff(); //Access overridden inherited member

virtual causes the derived type to be called.
so to call a base implementation, call the base member from within the derived type.

class Derived{  //<<edited code, put base instead of derived. sorry if confusion
  public:
    void DoStuff( void ){return;};
    virtual void DoOtherStuff( void ){dynamic_cast< Base& >( *this ).DoOtherStuff();};
};

Many other possibilities with inheritance, this is just an example.

Thanks!

Here is a more clear picture what I want to do:

I want to define a base class that is virtual, besides a few member properties, the member functions are all virtual, so a derived class will supply the actual implementation, which depends on which derived class, tactile switch or rotary encoder, or other button-like things. This way any button behaves the same when referred to base class methods, such as sense(). So I can instantiate a bunch of different buttons, some are straight tactile switches, some are rotary encoders and some are analog buttons. Then I can put them all in an array and iterates through the array, calling sense() for each button to see if any of them is pressed. I think this is much better than having a separate library for simple buttons, then some for keypads, and more for other types of buttons.

Something like this:

So maybe I don't need to call any method in base class since it's got no actual methods but anyway, any simple syntax to refer to a method in a base class if useful. Can I do this?

In derived class method, do this buttons.sense() to call the base class method, then do softwarebuttons.sense() to call the derived class method?

That seems fine to me. Just bear in mind you still have a library for each button type, they just share a common interface.
the base interface allows things like an array you were describing.

One draw back is unless you know the derived type of each element in the Buttons array you can only use the common interface with that object.

EDIT:
Yes you can define a base class that is just pure interface. If the derived classes use common memory that can be declared in the base, you can have non virtual base members like 'Reset'.

Right, this implementation aims at standardizing the way to interface different hardware for simplicity. I will most certainly have different library for each type of hardware and their special methods.

That a good reason for a library. Its exactly the same reason I am making a similar library. I have a system which I created for my lcd class that allows it to be connected in a parallel style or through shift registers. Once I finish I hope to extend it to spi.
This will allow any of the three wiring modes with only 1 line of code difference.

This is all reliant on inheritance

liudr:
So maybe I don't need to call any method in base class since it's got no actual methods but anyway, any simple syntax to refer to a method in a base class if useful. Can I do this?

In derived class method, do this buttons.sense() to call the base class method, then do softwarebuttons.sense() to call the derived class method?

If you have a "button" object and you call "sense()", "button::sense()" will get called. If you have a "softwarebutton" and you call "sense()", "softwarebutton::sense()" will get called.

A virtual method is only useful if you expect to have a button POINTER that is in fact pointing to a softwarebutton;

softwarebutton swb;
button* pb = &swb;
pb->sense();

In this case, softwarebutton::sense() will get called on swb.

Having virtual methods on a base interface-style class is useful when you want to pass around pointers to the base class. It's probably easiest to give an example from something I use. I have an "Updated" base class. It's really simple:

class Updated
{
public:
  virtual void update(void) = 0;
};

So anything which derives from "Updated" is something that I want to get updated every time through loop(), e.g.

class Siren: public Updated
{
  ... specific stuff to make a siren ...
public:
  virtual void update(void) { ...update my siren... }
};

The key here is that I will pass a pointer to my_siren to a method that expects a pointer to an Updated.

class UpdateManager
{
  ... other stuff to manage a list of Updated*'s ...
public:
  add(Updated* object) { ... add object to list of objects ... }
  void updateAll(void) { ... run through list of objects and call 'update' on each ... }
};

Then, in a sketch...

Siren my_siren;
UpdateManager upm;

void setup()
{
  upm.add(&my_siren);
}

void loop()
{
  upm.updateAll();
}

This will cause my_siren.update() to get called, even though the UpdateManager has no idea about a 'Siren' specifically, it just knows about the 'Updated' interface.

Here's a working example:

// number of items in an array
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))

class button 
 {
 int foo;  // internal variable
 
  public: 
  virtual int sense ();
 };
 
 class rotary_encoder : public button 
  {
  public: 
  virtual int sense (); 
  };
  
class push_button : public button 
  {
  public: 
  virtual int sense ();  
  };

int button::sense ()
  {
   Serial.println ("Sensing ...");
   return 0; 
  }
 
 int rotary_encoder::sense ()
  {
   return 42; 
  }
  
 int push_button::sense ()
  {
   return 55; 
  }
  
 rotary_encoder re1, re2;
 push_button pb1, pb2;
  
  button * buttons [] = { &re1, &re2, &pb1, &pb2 };
  
  void setup ()
  {
  Serial.begin (115200);
  
  for (byte i = 0; i < NUMITEMS (buttons); i++)
   Serial.println (buttons [i]->sense ()); 
  }  // end setup
  
  void loop () {}

That prints:

42
42
55
55

That clearly shows the derived class is being called. If you change the two derived sense functions to add a base-class call:

 int rotary_encoder::sense ()
  {
   button::sense ();
   return 42; 
  }
  
 int push_button::sense ()
  {
   button::sense ();
   return 55; 
  }

Then you see:

Sensing ...
42
Sensing ...
42
Sensing ...
55
Sensing ...
55

Nick,

Thanks for the crash course. Exactly what I needed. Just one question:

Do you have to declare the sense as "virtual" even in derived classes?

maniacbug,

The idea of updateall is pretty cool. How do you implement it? Do you have an array of objects that can be updated and just iterate all items in the array?

liudr:
The idea of updateall is pretty cool. How do you implement it? Do you have an array of objects that can be updated and just iterate all items in the array?

Yes it is most probably an array. The updatemanager class knows the base.

virtual is not required, but when extending your interfaces further things change.

if B derives A

and C derives B,

A's virtual member functions in B need to be virtual for C to overload them.
Otherwise A's member functions are described in B but only inherited in C.

liudr:
Do you have to declare the sense as "virtual" even in derived classes?

No, although it is good documenting practice to do so.

If you don't declare it in the base class however then my example compiles, but prints 0 as the sense result. This is because in the absence of the "virtual" keyword the compiler does not indirect the function calls via a vtable (virtual table) and "knows" that it can generate code to call the class directly.

So, virtual classes have an overhead, but give you flexibility.

Just as a little "gotcha", if you are going to do this, and use destructors, then the base class must have its destructor declared virtual too. Otherwise when the object goes out of scope the wrong destructor can/will be called, resulting in memory leaks or much worse.

liudr:
Do you have to declare the sense as "virtual" even in derived classes?

Yep, like Nick says, not technically required. Very rarely is there a situation where you really need to. But it's useful for those reading the code.

liudr:
The idea of updateall is pretty cool. How do you implement it? Do you have an array of objects that can be updated and just iterate all items in the array?

An array of Updated* 's. In this case I use a fixed size array. In other implementations of similar constructs I've malloc'd an array of base object pointers at runtime.

Thank you every one! I think I pretty much got all the ingredients for the new buttons class except for hard work. Maybe the winter break :slight_smile: