C++ 解决C++;基类的虚函数
对不起,如果这是一个骗局,我找不到一个完全正确的答案 我想从基类成员调用函数,并将其解析为子类版本。我原以为声明它是虚拟的就可以了,但事实并非如此。以下是我的方法:C++ 解决C++;基类的虚函数,c++,inheritance,virtual-functions,C++,Inheritance,Virtual Functions,对不起,如果这是一个骗局,我找不到一个完全正确的答案 我想从基类成员调用函数,并将其解析为子类版本。我原以为声明它是虚拟的就可以了,但事实并非如此。以下是我的方法: class GUIWindow { public: GUIWindow() { SetupCallbacks(); } virtual void SetupCallbacks() { // This function always called }
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 :(
我做错了什么
非常感谢
Si快速回答是,您可能需要在
GUIListbox
中声明一个构造函数,该构造函数调用SetupCallbacks
。原因更为复杂:因为GUIListbox不声明构造函数,当您声明该类型的对象时,将调用GUIWindow
构造函数。当GUIWindow
构造函数运行时,对象还不是GUIListbox。从编译器的角度来看,只有在该类的(空)构造函数启动后,它才会变成GUIListbox。因此,当第一个构造函数运行时,将调用GUIWindow中的方法。IOWs,这不起作用,而且永远不会像你希望的那样在C++中工作。
下面是一个详细描述此陷阱的参考:
这里是我最喜欢的C++资源的一个解释:
您的派生类型尚未构建。Class Cat : Animal
{
//...
};
创建Cat对象时,会发生以下情况:
GUIListbox lb;
lb.SetupCallbacks();
虚拟的意义在于,您可以执行以下操作:
GuiWindow *lb = new GuiListbox();
lb->SetupCallback();//Gets correctly resolved to GuiListBox's version
问题是您试图从构造函数调用虚拟函数。基类构造函数在派生类的构造函数之前被调用,因此当基类构造函数运行时,还没有创建对象的“派生部分” 在基类构造函数完成并且派生类构造函数启动之前,对象的行为将类似于基类类型的对象。这意味着对虚拟函数的调用不会调用派生类中定义的实现,它们只会执行基类中的版本
在“类代码>代码< >代码>(即当代码< C/代码>的构造器是活动的)时,调用C++函数FAQ Lite和
< P>,虚拟机制工作,但它以受限模式工作。类层次结构中虚拟调用的解析受当前正在构造的类(C
)的限制。这意味着虚拟调用将解析为类C
是层次结构中的“最终”类,就好像它没有子类一样
析构函数也是如此
在您的示例中,您正在从类GUIWindow
的构造函数调用一个虚拟函数。只要GUIWindow
的构造函数处于活动状态,它的虚拟机制就会像没有其他类从GUIWindow
派生一样工作。此机制将完全忽略GUIListbox
类的存在。这就是为什么虚拟调用的解析“停止”在GUIWindow
并调用GUIWindow::SetupCallbacks
,就好像GUIListbox::SetupCallbacks
不存在一样
你可以在C++中找到有关FAQ的内容
+1@sipickles,您正在从基类的构造函数调用虚方法——甚至在初始化对象的派生部分之前。即使它确实调用了派生类型的方法,对于未初始化的部分,您希望它的行为是什么?:)如果这本书实际上是这么说的,那么放这本书的地方就是垃圾桶。这本书实际上似乎在暗示“你太蠢了,不知道它是如何工作的,所以永远不要去做”。实际上,正确的建议应该是“了解虚拟函数在构建过程中如何工作以及如何正确使用它们”。虚拟功能在施工过程中确实有效,但有一些细节。谢谢。这是显而易见的!是时候重读我的课本了!或者,最简单的答案是:GUIWindow构造函数构造一个GUIWindow。