错误的调用约定导致的运行时错误

时间:2011-12-06 16:13:55

标签: visual-c++ runtime-error calling-convention

我有以下类定义:

class IRenderable {
 public:

    virtual void Render( wxBitmap * ) = 0;
}

class MyClass : public wxWindow, public IRenderable {

public:

/* costructor, destructor etc... */


    void RenderBitmap( wxBitmap *bitmap )
    {
        // code
    }

}

其中wxWindow和wxBitmap是属于wxWidgets库的类(用于编写GUI应用程序的C ++可移植库)。

我正在使用Visual C.以下代码错误:

MyClass *c = new MyClass(...);
wxWindow *w = (wxWindow *)c;
IRenderable *r_page = (IRenderable *)w;
// bitmap is allocate somewhere else           
r_page->RenderBitmap( bitmap );

因为我收到运行时错误:

  

运行时检查失败#0 - 未正确保存ESP的值   跨函数调用。这通常是调用a的结果   用一个带有函数指针的调用约定声明的函数   用不同的调用约定声明。

发生了什么事?

我正在做的是以下内容。第三方库(wxAUI)获取指向wxWindow的指针以便管理它们。我已经sublcassed wxWindow(MyClass)添加一些特定的代码。因此,我使用的是MyClass对象,而不是管理wxWindows对象。 在某些情况下,我要求wxAUI返回“当前”窗口的wxWindow指针,该指针应该是指向MyClass对象的指针。我想在这些对象上调用RenderBitmap()方法,所以我需要将它转换为IRenderable,但是得到运行时错误......

我没有启用RTTI,如果这样可以解决问题,现在就不行了......

1 个答案:

答案 0 :(得分:1)

问题在于:

IRenderable *r_page = (IRenderable *)w;

w未指向IRenerable个实例。我明白为什么你会这么认为,但事实并非如此。

避免从多个类继承,并谷歌“钻石继承”和“虚拟继承”以便更好地理解。

从钻石问题的wikipedia article中摘录:

  

默认情况下,C ++分别跟随每个继承路径,因此是D对象   实际上会包含两个单独的A对象,以及A成员的使用   必须得到适当的资格。如果继承从A到B和   从A到C的继承都标记为“虚拟”(例如,“class”   B:虚拟公共A“),C ++特别注意只创建一个A.   对象和A成员的使用正常工作。如果虚拟继承   和非虚拟继承是混合的,有一个虚拟的A和   A的每个非虚拟继承路径的非虚拟A。请注意   在这种情况下,A的非虚拟推导将是无用的直接   从D类访问A类的任何部分几乎总是会结束   编译错误。