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对象时,会发生以下情况:

  • 构造动物
  • 构造猫
  • 当对象超出范围或通过堆上的delete if销毁时,会发生以下情况:

  • 破坏猫
  • 破坏动物
  • 因此,不应在构造函数或析构函数中调用虚拟函数。如果基类中没有实现,您甚至会有一个

    您必须:

    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。