Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

CBuilder игнорирует виртуальный конструктор...

1.8K
04 апреля 2011 года
Arkady
153 / / 18.12.2007
Всем привет.

Есть класс
Код:
class C_UnknownStub : public IUnknown
{
private:
    volatile long m_cRef;
public:
    C_UnknownStub();
    virtual ~C_UnknownStub();

    virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();
};

Который реализует некоторую "заглушку" для интерфейса IUnknown.

От него наследуется:
Код:
class I_StringsList : public C_UnknownStub
{
public:
    virtual void clear() = 0;
    virtual void push_back(const char*) = 0;
    virtual unsigned size() = 0;
    virtual const char* Get(unsigned i) = 0;
};

class C_StringList : public I_StringsList
{
private:
    C_VectorW<C_StringW> m_SV;

public:
    C_StringList(){ }
    C_StringList(C_VectorW<C_StringW>& newSV)
    {
        m_SV = newSV;
    }
    virtual ~C_StringList() {}

    virtual void clear() { m_SV.clear(); }
    virtual void push_back(char* string)
    {
        C_StringW Temp(string);
        m_SV.push_back(Temp);
    }
    virtual unsigned size() {   return m_SV.size(); }
    virtual const char* Get(unsigned i) {  return m_SV.c_str(); }
};


Формируется DLL, собранная Builder, которая имеет метод
 
Код:
I_StringsList* GetStrings();

Внутри она создает экземпляр класса C_StringList и возвращает указатель на него пользователю.

Если клиент к этой DLL написан на CBuilder, то все работает корректно.
Если же клиент написан на Qt, то указатель на I_StringsList* имеет сдвиг:
при вызове метода size() реально вызывается метод Get(), при вызове метода Push_back(...), вызывается метод size(). Т.е. сдвиг на один метод. Как будто один метод потерялся в таблице Builder.

Таблица виртуальных функций, построенная CBuilder:
0) virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);
1) virtual ULONG __stdcall AddRef();
2) virtual ULONG __stdcall Release();
3) virtual void clear() = 0;
4) virtual void push_back(const char*) = 0;
5) virtual unsigned size() = 0;
6) virtual const char* Get(unsigned i) = 0;

Таблица виртуальных функций, построенная Qt:
0) virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);
1) virtual ULONG __stdcall AddRef();
2) virtual ULONG __stdcall Release();
3) virtual ~C_UnknownStub();
4) virtual void clear() = 0;
5) virtual void push_back(const char*) = 0;
6) virtual unsigned size() = 0;
7) virtual const char* Get(unsigned i) = 0;

В таком случае правда, если в QT мы вызываем size(), он идет под номером 6, и вызывает метод Get() объекта, созданного в CBuilder.

Сборка без виртуального деструктора у C_UnknownStub показала, что все работает корректно.

Вопрос 1: почему CBuilder теряет виртуальный деструктор в своей таблице виртуальных функций?
Вопрос 2: как корректно решить эту проблему? :)

Заранее спасибо за участие, проблема, имхо, очень специфична.
535
04 апреля 2011 года
Нездешний
537 / / 17.01.2008
Попробуйте определить виртуальный деструктор для I_StringsList.
 
Код:
class I_StringsList : public C_UnknownStub
{
public:
    virtual ~I_StringsList() {}

    virtual void clear() = 0;
    virtual void push_back(const char*) = 0;
    virtual unsigned size() = 0;
    virtual const char* Get(unsigned i) = 0;
};


Ну и как-то подозрительно, что сигнатуры виртуального метода I_StringsList:: push_back и метода C_StringList:: push_back немного не совпадают. В одном случае аргумент const char*, в другом - char*
1.8K
04 апреля 2011 года
Arkady
153 / / 18.12.2007
Цитата: Нездешний
Попробуйте определить виртуальный деструктор для I_StringsList.
 
Код:
class I_StringsList : public C_UnknownStub
{
public:
    virtual ~I_StringsList() {}

    virtual void clear() = 0;
    virtual void push_back(const char*) = 0;
    virtual unsigned size() = 0;
    virtual const char* Get(unsigned i) = 0;
};


Ну и как-то подозрительно, что сигнатуры виртуального метода I_StringsList:: push_back и метода C_StringList:: push_back немного не совпадают. В одном случае аргумент const char*, в другом - char*


Да, там в обоих случаях const char*. И попробовал, сделал так всюду, проблема осталась.

535
05 апреля 2011 года
Нездешний
537 / / 17.01.2008
А тело у virtual ~C_UnknownStub() есть какое-нибудь? Хотя бы {}?
1.8K
05 апреля 2011 года
Arkady
153 / / 18.12.2007
Цитата: Нездешний
А тело у virtual ~C_UnknownStub() есть какое-нибудь? Хотя бы {}?


Да. Мы вообще, борясь с проблемой, пришли к такому:

Код:
#pragma pack(push,4)
class IF
{
public:
 virtual __stdcall IF() {}
 virtual __stdcall Func() = 0;
};
#pragma pack(pop)

#pragma pack(push,4)
class RIF : public IF
{
public:
 virtual __stdcall ~RIF() {}
  virtual __stdcall Func() { MessageBox(NULL, "sdf", "wer", MB_OK); }
};
#pragma pack(pop)

Так вот, dll (сделанная на Билдере) имеет метод CreateInstance, который возвращает по интерфейсу IF объект RIF.
Если возвращает Билдеру, то все отлично. Если возвращает в Qt, то при вызове метода Func получаем segmentation fault.

Если реализующий класс выглядит так
Код:
#pragma pack(push, 4)
class RIF : public IF
{
public:
 virtual __stdcall ~RIF() {}
  virtual __stdcall Func1() { MessageBox(NULL, "sdf1", "wer", MB_OK); }
  virtual __stdcall Func2() { MessageBox(NULL, "sdf2", "wer", MB_OK); }
  virtual __stdcall Func3() { MessageBox(NULL, "sdf3", "wer", MB_OK); }
  virtual __stdcall Func4() { MessageBox(NULL, "sdf4", "wer", MB_OK); }
  virtual __stdcall Func() { MessageBox(NULL, "sdf", "wer", MB_OK); }
};
#pragma pack(pop)

То при вызове Func, получаем MessageBox "sdf1".
Т.е. сдвиг на два указателя вниз идет.
(в таблице-то виртуальных функций они идут в таком порядке: Func, ~~RIF, Func1, Func2...)

На другом форуме один человек собрал свою dll под билдером, проверил ее с Qt, использующим компилятор VS, все нормально.
Его же dll, при попытке вызова в Qt с компилятором minGW, уже у нас, дает ту же проблему.

Я развожу руками, понятия не имею, что еще можно сделать, чтобы указатели в таблицу виртуальных функций совпадали =(
1.8K
05 апреля 2011 года
Arkady
153 / / 18.12.2007
Цитата: Arkady
Да. Мы вообще, борясь с проблемой, пришли к такому:
Т.е. сдвиг на два указателя вниз идет.
(в таблице-то виртуальных функций они идут в таком порядке: Func, ~~RIF, Func1, Func2...)



Было проведено исследование:
если убрать оба деструктора, то при вызове метода Func, вызывается метод Func2
если оставить деструктор интерфейса, деструктор реализации или оба деструктора, то при вызове метода Func, вызывается метод Func1.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог