Ни базовая, ни производная виртуальная функция не называются должным образом

У меня есть этот базовый класс:

// put the display in a macro on a .h file for less headache.
class Gadget {
  protected:
    int x, y;
    U8GLIB * u8g;

    virtual int  f_focus()  {return 0;};
    virtual int  f_blur()   {return 0;};
    virtual void f_draw()   {};
    virtual void f_select() {};


  public:
    Gadget(U8GLIB * u8g, int x, int y) :
      u8g(u8g),
      x(x),
      y(y)
    {
      Serial.println(F("Gadget(U8GLIB * u8g, int x, int y)"));
    };

    Gadget() {
      Serial.println(F("Gadget()"));
    };

    int     focus(){return f_focus();};
    int     blur(){return f_blur();};
    void    draw(){f_draw();};
    void    operator()(){f_select();};
};

И этот производный класс:

class WakeUp :
  public Gadget
{
  public:
    WakeUp(U8GLIB * u8g) :
      Gadget(u8g, 0, 0)
    {
      Serial.println(F("WakeUp(U8GLIB * u8g)"));
    };

};

Затем я создаю экземпляр класса WakeUp внутри массива следующим образом:

Gadget gadgets[1] = {
  WakeUp(&u8g)
};

Затем я пытаюсь получить доступ к этому члену, как это:

void focus() {
  Serial.println(gadgets[0].focus());
}  

Должен отображать 0, Однако это отображает -64, Даже если я переопределю f_focus() метод на WakeUp учебный класс. Если я удалю virtual спецификатор от f_focus() работает нормально, отображается 0, но я не смогу получить доступ к производной реализации класса этого метода. Я хочу понять, что вызывает это странное поведение и что я могу сделать, чтобы избежать этого.

РЕДАКТИРОВАТЬ:

Функция работает нормально, если я вызываю ее из Gadget Конструктор.

1 ответ

Решение

Вы режете свой WakeUp объект.

По сути, у вас есть следующее:

Gadget g = WakeUp(...);

Этот код делает следующее:

  1. Построить WakeUp объект.
  2. Вызов Gadget(const Gadget& other) с основанием из WakeUp объект.
  3. Уничтожить временный WakeUp объект, оставляя только копию Gadget база.

Чтобы избежать этого, вам нужно создать массив указателей (лучше, если они умные указатели).

Gadget* gadgets[1] = { new WakeUp(&u8g) }; // If you choose this method, you need to call 
                                           // delete gadget[0] or you will leak memory.

Использование указателя правильно сохранит Gadget а также WakeUp экземпляры вместо того, чтобы отрезать их.

С умными указателями:

std::shared_ptr<Gadget> gadgets[1] = { std::make_shared<WakeUp>(&u8g) };
Другие вопросы по тегам