基函数和派生虚函数都没有被正确调用
Nor base nor derived virtual function being properly called
我有这个基地class:
// 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:
class WakeUp :
public Gadget
{
public:
WakeUp(U8GLIB * u8g) :
Gadget(u8g, 0, 0)
{
Serial.println(F("WakeUp(U8GLIB * u8g)"));
};
};
然后我在数组中实例化唤醒 class,如下所示:
Gadget gadgets[1] = {
WakeUp(&u8g)
};
然后我尝试像这样访问这个成员:
void focus() {
Serial.println(gadgets[0].focus());
}
应该显示0
。但是它显示 -64
。即使我覆盖 WakeUp
class 上的 f_focus()
方法。如果我从 f_focus()
中删除 virtual
说明符,它工作正常,显示 0
,但我将无法访问此方法的派生 class 实现。
我想了解是什么导致了这种奇怪的行为,我该怎么做才能避免这种情况。
编辑:
如果我从 Gadget
构造函数中调用该函数,该函数运行良好。
您正在切割 WakeUp
对象。
你基本上有以下内容:
Gadget g = WakeUp(...);
这段代码的作用如下:
- 构造一个
WakeUp
对象。
- 使用
WakeUp
对象的基础调用 Gadget(const Gadget& other)
。
- 销毁临时
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) };
我有这个基地class:
// 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:
class WakeUp :
public Gadget
{
public:
WakeUp(U8GLIB * u8g) :
Gadget(u8g, 0, 0)
{
Serial.println(F("WakeUp(U8GLIB * u8g)"));
};
};
然后我在数组中实例化唤醒 class,如下所示:
Gadget gadgets[1] = {
WakeUp(&u8g)
};
然后我尝试像这样访问这个成员:
void focus() {
Serial.println(gadgets[0].focus());
}
应该显示0
。但是它显示 -64
。即使我覆盖 WakeUp
class 上的 f_focus()
方法。如果我从 f_focus()
中删除 virtual
说明符,它工作正常,显示 0
,但我将无法访问此方法的派生 class 实现。
我想了解是什么导致了这种奇怪的行为,我该怎么做才能避免这种情况。
编辑:
如果我从 Gadget
构造函数中调用该函数,该函数运行良好。
您正在切割 WakeUp
对象。
你基本上有以下内容:
Gadget g = WakeUp(...);
这段代码的作用如下:
- 构造一个
WakeUp
对象。 - 使用
WakeUp
对象的基础调用Gadget(const Gadget& other)
。 - 销毁临时
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) };