解决C++来自基类的虚函数

发布于 2024-08-23 17:00:12 字数 501 浏览 10 评论 0原文

抱歉,如果这是一个骗局,我找不到正确的答案。

我想从基类成员调用函数,并将其解析为子类版本。我以为声明它是虚拟的就可以了,但事实并非如此。这是我的方法:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甩你一脸翔 2024-08-30 17:00:12

当您在构造某些类 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 of C 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 class C 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 of GUIWindow is active, its virtual mechanism will work as if there are no other classes derived from GUIWindow. This mechanism will completely ignore the existence of GUIListbox class. This is why the resolution of virtual call "stops" at GUIWindow and calls GUIWindow::SetupCallbacks, as if GUIListbox::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

萝莉病 2024-08-30 17:00:12

您的派生类型尚未构造。

Class Cat : Animal
{
//...
};

当您创建一个 Cat 对象时,会发生以下情况:

  1. 构造动物
  2. 构造猫

当您的对象超出范围或通过删除(如果在堆上)被销毁时,会发生以下情况:

  1. 析构猫
  2. 析构动物

因此,您不应调用虚函数在你的构造函数或析构函数中。你甚至会有一个 纯虚函数如果您的基类中没有实现,请调用

您必须:

GUIListbox lb;
lb.SetupCallbacks();

虚拟的目的是让您可以执行以下操作:

GuiWindow *lb = new GuiListbox();
lb->SetupCallback();//Gets correctly resolved to GuiListBox's version

Your derived type is not constructed yet.

Class Cat : Animal
{
//...
};

When you create a create a Cat object the following happens:

  1. Construct Animal
  2. Construct Cat

When your object goes out of scope or gets destroyed via delete if on the heap, the following happens:

  1. Destruct Cat
  2. Destruct Animal

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:

GUIListbox lb;
lb.SetupCallbacks();

The point of virtual is so that you can do things like:

GuiWindow *lb = new GuiListbox();
lb->SetupCallback();//Gets correctly resolved to GuiListBox's version
浮萍、无处依 2024-08-30 17:00:12

问题是您试图从构造函数中调用虚函数。基类构造函数在派生类构造函数之前调用,因此当基类构造函数运行时,对象的“派生部分”尚未创建。

该对象的行为类似于基类类型的对象,直到基类构造函数完成并且派生类构造函数开始。这意味着对虚函数的调用不会调用派生类中定义的实现,它们只会执行基类中的版本。

另请参阅 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.

紫南 2024-08-30 17:00:12

简单的答案是,您可能必须在 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 calls SetupCallbacks. The reason is more complicated: because GUIListbox doesn't declare a constructor, when you declare an object of that type the GUIWindow constructor is called. When the GUIWindow 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文