解决C++来自基类的虚函数
抱歉,如果这是一个骗局,我找不到正确的答案。
我想从基类成员调用函数,并将其解析为子类版本。我以为声明它是虚拟的就可以了,但事实并非如此。这是我的方法:
class GUIWindow
{
public:
GUIWindow()
{
SetupCallbacks();
}
virtual void SetupCallbacks()
{
// This function always called
}
};
class GUIListbox : public GUIWindow
{
public:
void SetupCallbacks()
{
// This never called
}
};
GUIListbox lb; // GUIWindow::SetupCallbacks is called :(
我做错了什么?
非常感谢
斯
Sorry if this is a dupe, I cant find an answer quite right.
I want to call a function from a base class member, and have it resolve to the subclass version. I thought declaring it virtual would do it, but it isn't. Here's my approach:
class GUIWindow
{
public:
GUIWindow()
{
SetupCallbacks();
}
virtual void SetupCallbacks()
{
// This function always called
}
};
class GUIListbox : public GUIWindow
{
public:
void SetupCallbacks()
{
// This never called
}
};
GUIListbox lb; // GUIWindow::SetupCallbacks is called :(
What am I doing wrong?
Many thanks
Si
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
永远不要在构造函数中调用虚函数。
Never call a virtual function in the constructor.
当您在构造某些类
C
期间调用虚函数时(即当C
的构造函数处于活动状态时),虚机制起作用,但它在受限模式下工作。类层次结构中虚拟调用的解析受当前正在构造的类 (C
)限制。这意味着虚拟调用将被解析,就好像类C
是层次结构中的“最终”类,就好像它没有后代一样。对于析构函数也是如此。
在您的示例中,您从 GUIWindow 类的构造函数调用虚拟函数。只要
GUIWindow
的构造函数处于活动状态,它的虚拟机制就会像没有从GUIWindow
派生的其他类一样工作。这种机制将完全忽略GUIListbox
类的存在。这就是为什么虚拟调用的解析在GUIWindow
处“停止”并调用GUIWindow::SetupCallbacks
,就好像GUIListbox::SetupCallbacks
没有这样做一样。存在。您可以在 C++ FAQ 中阅读有关内容
http://www.parashift.com/c++- faq-lite/strange-inheritance.html#faq-23.5
When you call virtual functions during construction of some class
C
(i.e. while the constructor ofC
is active), the virtual mechanism works, but it works in restricted mode. The resolution of the virtual calls in the class hierarchy is limited by the class that is currently being constructed (C
). This means that the virtual calls will resolve as if the classC
is the "final" class in the hierarchy, as if it has no descendants.The same is true for destructors.
In your example, you are calling a virtual function from constructor of class
GUIWindow
. As long as the constructor ofGUIWindow
is active, its virtual mechanism will work as if there are no other classes derived fromGUIWindow
. This mechanism will completely ignore the existence ofGUIListbox
class. This is why the resolution of virtual call "stops" atGUIWindow
and callsGUIWindow::SetupCallbacks
, as ifGUIListbox::SetupCallbacks
doesn't exist.You can read about in in C++ FAQ
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5
您的派生类型尚未构造。
当您创建一个 Cat 对象时,会发生以下情况:
当您的对象超出范围或通过删除(如果在堆上)被销毁时,会发生以下情况:
因此,您不应调用虚函数在你的构造函数或析构函数中。你甚至会有一个 纯虚函数如果您的基类中没有实现,请调用。
您必须:
虚拟的目的是让您可以执行以下操作:
Your derived type is not constructed yet.
When you create a create a Cat object the following happens:
When your object goes out of scope or gets destroyed via delete if on the heap, the following happens:
For this reason you should not call virtual functions in your constructor or destructor. You would even have a pure virtual function call if you did not have an implementation in your base class.
You are going to have to:
The point of virtual is so that you can do things like:
问题是您试图从构造函数中调用虚函数。基类构造函数在派生类构造函数之前调用,因此当基类构造函数运行时,对象的“派生部分”尚未创建。
该对象的行为类似于基类类型的对象,直到基类构造函数完成并且派生类构造函数开始。这意味着对虚函数的调用不会调用派生类中定义的实现,它们只会执行基类中的版本。
另请参阅 C++ FAQ Lite,了解更多详细信息 和可能的解决方法。
The problem is that you are trying to call the virtual function form the constructor. The base class constructor is called before the constructor of the derived class, so the "derived parts" of the object are not created yet when the base classes constructor runs.
The object will behave like an object of the base class type until the base classes constructor is finished and the derived classes constructor starts. This means that calls to virtual functions will not call implementations defined in the derived class, they will just execute the version from the base class.
Also see the C++ FAQ lite for more details and possible workarounds.
简单的答案是,您可能必须在
GUIListbox
中声明一个调用SetupCallbacks
的构造函数。原因更复杂:因为 GUIListbox 没有声明构造函数,所以当您声明该类型的对象时,会调用 GUIWindow 构造函数。当 GUIWindow 构造函数运行时,对象还不是 GUIListbox。从编译器的角度来看,只有当该类的(空)构造函数启动时,它才会变成 GUIListbox。因此,当第一个构造函数运行时,将调用 GUIWindow 中的方法。 IOWs,这行不通,并且在 C++ 中永远不会按照您想要的方式工作。以下是详细描述此陷阱的参考资料: http://www.artima.com/cppsource/nevercall .html。
以下是我最喜欢的 C++ 资源的解释: http://yosefk .com/c++fqa/inheritance-mother.html#fqa-23.5
The quick answer is that you may have to declare a constructor in
GUIListbox
which callsSetupCallbacks
. The reason is more complicated: because GUIListbox doesn't declare a constructor, when you declare an object of that type theGUIWindow
constructor is called. When theGUIWindow
constructor is running, the object isn't a GUIListbox yet. From the compiler's perspective, it only becomes a GUIListbox once the (empty) constructor for that class starts. So when the first constructor runs, the methods from GUIWindow are called. IOWs, this doesn't work, and will never work in C++ the way that you want it to.Here's a reference describing this pitfall in detail: http://www.artima.com/cppsource/nevercall.html.
And here's an explanation from my favorite C++ resource: http://yosefk.com/c++fqa/inheritance-mother.html#fqa-23.5