Ошибка времени выполнения, вызванная неправильным соглашением о вызовах - PullRequest
0 голосов
/ 06 декабря 2011

У меня есть следующее определение класса:

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 (переносимая библиотека 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 не было сохранено должным образом через вызов функции. Обычно это результат вызова функция объявлена ​​с одним соглашением о вызовах с указателем на функцию объявлено с другим соглашением о вызовах.

Что происходит?

Что я делаю, так это следующее. Сторонняя библиотека (wxAUI) получает указатели на wxWindow для управления ими. Я вставил wxWindow (MyClass), чтобы добавить определенный код. Поэтому вместо управления объектами wxWindows я использую объекты MyClass. В некоторых ситуациях я прошу wxAUI вернуть мне указатель wxWindow «текущего» окна, который должен быть указателем на объект MyClass. Я хочу вызвать метод RenderBitmap () для этих объектов, поэтому мне нужно привести его к IRenderable, но получить эту ошибку во время выполнения ...

У меня нет разрешения RTTI и нет сейчас, если это решит проблему ...

1 Ответ

1 голос
/ 06 декабря 2011

Проблема здесь:

IRenderable *r_page = (IRenderable *)w;

w не указывает на экземпляр IRenerable.Я понимаю, почему вы думаете, что это так, но это не так.

Избегайте наследования от нескольких классов, а также Google "Diamond наследование" и "виртуальное наследование" для лучшего понимания.

Извлечение из статьи Википедии о проблеме алмаза:

C ++ по умолчанию следует каждому пути наследования отдельно, поэтому объект D на самом деле будет содержать два отдельных объекта A и использует AЧлены должны быть надлежащим образом квалифицированы.Если наследование от A до B и наследование от A до C помечены как «виртуальные» (например, «класс B: виртуальный общедоступный A»), C ++ уделяет особое внимание созданию только одного объекта A и использует членов Aработать правильно.Если виртуальное наследование и невиртуальное наследование смешаны, то для каждого пути невиртуального наследования к A. существует один виртуальный A и не виртуальный A. Обратите внимание, что невиртуальное наследование A в этом случае будет бесполезным, так как прямой доступ к любой части класса A изкласс D практически всегда заканчивается ошибкой компиляции.

...