-4

I have a base and a derived class:

plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H

// plugin states
#define PLUGIN_IDLE 0

class Plugin {
public:
  Plugin();
  ~Plugin();

  virtual void loop();
};

#endif

plugin.cpp

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

Plugin::Plugin() {
}

Plugin::~Plugin(){
}

void Plugin::loop(){
  Serial.println("Plugin::loop()");
}

derived class

class OneWirePlugin : public Plugin {
public:
  OneWirePlugin(byte pin);
  void loop();
};

OneWirePlugin::OneWirePlugin(byte pin) {
}

void OneWirePlugin::loop() {
  Serial.println("OneWirePlugin::loop()");
}

I was expecting that calling the derived instance's loop() method would execute OneWirePlugin::loop().

However, this only happens when I call it in derived class context:

Plugin p = Plugin();
Plugin o = OneWirePlugin(ONEWIRE_PIN);
OneWirePlugin q = OneWirePlugin(ONEWIRE_PIN);
p.loop(); // Plugin::loop()
o.loop(); // Plugin::loop()
q.loop(); // OneWirePlugin::loop()

What's wrong with my virtual method that will allow be calling the derived implementation, especially when referenced via *Plugin pointers?

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
andig
  • 13,378
  • 13
  • 61
  • 98

2 Answers2

7

loop must be declared as virtual:

class Plugin {

// ...

virtual void loop();

Also, for the polymorphism to work, you need a pointer or a reference:

Plugin* o = new OneWirePlugin(ONEWIRE_PIN);
o->loop();

// ...

delete o;

(in your code, slicing occurs, as noted by Mat in the comments section)

And then, consider using smart pointers (like unique_ptr or shared_ptr).


If you're using C++11 you should also mark loop with the override specifier in subclasses:

class OneWirePlugin : public Plugin {

// ...

void loop() override { 
Community
  • 1
  • 1
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
  • `make_unique` is no better than `new`. – SergeyA Jan 08 '16 at 16:15
  • 1
    @SergeyA Slightly better, because you don't need `delete`. – BartoszKP Jan 08 '16 at 16:16
  • can you please elaborate? I am not following this. – SergeyA Jan 08 '16 at 16:16
  • @SergeyA Elaborate on what? Perhaps I've misunderstood your comment. – BartoszKP Jan 08 '16 at 16:17
  • @SergeyA Missing `delete` in various situations (e.g. exceptions thrown) is a common error when hand coding `new`. – πάντα ῥεῖ Jan 08 '16 at 16:18
  • @πάνταῥεῖ, BartoszKP, someone is missing something there. My comment was only related to 'consider not using new directly, but switching to unique_ptr or shared_ptr' - and I meant to say, there is nothing wrong with using `unique_ptr` and `new` together - I know some ppl advocate for `make_unique` instead of `new`, but I do not see any benefits.. – SergeyA Jan 08 '16 at 16:21
  • @SergeyA OK, now I understand. I was not aware of this controversy, so I'm grateful that you've mentioned it. However, this question seems to set a context that is too basic for this kind of discussion. The point of this part of my answer was only to encourage smart pointers, nothing more :) – BartoszKP Jan 08 '16 at 16:24
  • Arduino does not allow C++11 yet through the IDE. – andig Jan 08 '16 at 16:26
  • 1
    @andig At least there is `std::auto_ptr<>` for pre C++11 code. It's still better than using a raw pointer. – πάντα ῥεῖ Jan 08 '16 at 16:30
  • @andig Since version 1.5.7 you can enable C++11, and 1.6.6 and above have it enabled by default. However there is no standard library support, so no auto/shared/unique pointers. – Chris A Jan 08 '16 at 16:59
0

In your question - 1. Plugin p = new Plugin(); 2. Plugin o = OneWirePlugin(ONEWIRE_PIN);

  1. will call Plugin::loop() as it base class object .
  2. will also call Plugin::loop() as you are creating Plugin object and this way object slicing occurs to form base class object from derived class object .

Below example will help .

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

Run on IDE Object slicing happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object.

Adya
  • 58
  • 5