Arduino 未正确调用基虚函数或派生虚函数

Arduino 未正确调用基虚函数或派生虚函数,arduino,arduino-c++,Arduino,Arduino C++,我有一个基本类: // 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() {};

我有一个基本类:

// 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());
}  
然后,我尝试如下方式访问此成员:

Gadget gadgets[1] = {
  WakeUp(&u8g)
};
void focus() {
  Serial.println(gadgets[0].focus());
}  
它应该显示
0
。但是,它正在显示
-64
。即使我重写了
WakeUp
类上的
f_focus()
方法。如果我从
f_focus()
中删除
virtual
说明符,它可以正常工作,显示
0
,但我将无法访问此方法的派生类实现。 我想了解是什么导致了这种奇怪的行为,我能做些什么来避免它

编辑:


如果我从
Gadget
构造函数调用该函数,该函数运行良好。

您正在切片
唤醒对象

您基本上有以下几点:

Gadget g = WakeUp(...);
此代码的作用如下:

Gadget g = WakeUp(...);
  • 构造一个
    唤醒对象
  • 使用
    唤醒
    对象中的基址调用
    小工具(const Gadget&other)
  • 销毁临时
    唤醒
    对象,只留下
    小工具
    库的副本
  • 为了避免这种情况,您需要创建一个指针数组(如果它们是智能指针,这会更好)

    使用指针将正确保留
    小工具
    唤醒
    实例,而不是将它们切掉

    使用智能指针:

    std::shared_ptr<Gadget> gadgets[1] = { std::make_shared<WakeUp>(&u8g) };
    
    std::shared_ptr gadgets[1]={std::make_shared(&u8g)};
    
    您正在切片
    唤醒对象

    您基本上有以下几点:

    Gadget g = WakeUp(...);
    
    此代码的作用如下:

    Gadget g = WakeUp(...);
    
  • 构造一个
    唤醒对象
  • 使用
    唤醒
    对象中的基址调用
    小工具(const Gadget&other)
  • 销毁临时
    唤醒
    对象,只留下
    小工具
    库的副本
  • 为了避免这种情况,您需要创建一个指针数组(如果它们是智能指针,这会更好)

    使用指针将正确保留
    小工具
    唤醒
    实例,而不是将它们切掉

    使用智能指针:

    std::shared_ptr<Gadget> gadgets[1] = { std::make_shared<WakeUp>(&u8g) };
    
    std::shared_ptr gadgets[1]={std::make_shared(&u8g)};
    
    在将返回值传递给
    串行.println
    之前,是否必须将其转换为字符串?否。它接受整数值。
    小工具
    s数组包含的是
    小工具
    s,而不是小部件。如果要存储从
    Gadget
    派生的类的实例,需要一个
    std::unique_ptr
    s数组。我在arduino上没有stdlib。因此,我的小工具必须存储在一个数组中。Serial.println也接受整数。文件对此很清楚@量子物理学家虽然我感谢你的耐心和关于物体切片的传统信息,这是我直到今天才知道的,但是你在关于Serial.println的建议中遗漏了一些重要信息。它是一个arduino核心函数,在串行端口上打印它。它接受String(不是std::String,因为arduino不支持stdlib)、integer、float和char*。在将返回值传递到
    Serial.println
    之前,是否必须将其转换为String?否。它接受整数值。
    Gadget
    s数组包含
    Gadget
    s,而不是小部件。如果要存储从
    Gadget
    派生的类的实例,需要一个
    std::unique_ptr
    s数组。我在arduino上没有stdlib。因此,我的小工具必须存储在一个数组中。Serial.println也接受整数。文件对此很清楚@量子物理学家虽然我感谢你的耐心和关于物体切片的传统信息,这是我直到今天才知道的,但是你在关于Serial.println的建议中遗漏了一些重要信息。它是一个arduino核心函数,在串行端口上打印它。它接受String(不是std::String,因为arduino不支持stdlib)、integer、float和char*。我不能使用智能指针,因为我没有stdlib。但我将尝试使用普通指针或接口类。谢谢。@luiz写一篇
    notstd::unique_ptr
    既短又值得。我会试试看,因为我没有stdlib,所以我不能使用智能指针。但我将尝试使用普通指针或接口类。谢谢。@luiz写一篇
    notstd::unique_ptr
    既短又值得。我会试试看