Представьте себе вот что: есть окно CMyMegaWnd, наследованное от CFrameWindowImpl, кот. объявлен с ATL_NO_VTABLE и от некоторого класса CGGClass.
А можно ли имея казатель на CGGClass удалить весь объект CMyMegaWnd??
Здравствуйте, machine1, Вы писали:
M>Представьте себе вот что: есть окно CMyMegaWnd, наследованное от CFrameWindowImpl, кот. объявлен с ATL_NO_VTABLE и от некоторого класса CGGClass. M>А можно ли имея казатель на CGGClass удалить весь объект CMyMegaWnd??
Сам же __declspec(novtable) подавляет генерацию vtable в класcе следовательно ты не можешь вызывать виртуальные функций этого класса из производного. Обычно ATL_NO_VTABLE ставят на последний класс в цепочке наследования.
include <stdio.h>
class __declspec(novtable) X
{
public:
virtual void mf();
};
class Y : public X
{
public:
void mf()
{
}
};
int main()
{
X *pX = new X();
pX->mf(); // Вот здесь будет AV
}
... << RSDN@Home 1.1.4 beta 3 rev. 0>>
Re[2]: ATL_NO_VTABLE и все такое..
От:
Аноним
Дата:
11.11.04 09:16
Оценка:
Здравствуйте, NKZ, Вы писали:
NKZ>Определение макроса ATL_NO_VTABLE следующее:
NKZ>
NKZ>Сам же __declspec(novtable) подавляет генерацию vtable в класcе следовательно ты не можешь вызывать виртуальные функций этого класса из производного. Обычно ATL_NO_VTABLE ставят на последний класс в цепочке наследования.
NKZ>
NKZ>include <stdio.h>
NKZ>class __declspec(novtable) X
NKZ>{
NKZ>public:
NKZ> virtual void mf();
NKZ>};
NKZ>class Y : public X
NKZ>{
NKZ>public:
NKZ> void mf()
NKZ> {
NKZ> }
NKZ>};
NKZ>int main()
NKZ>{
NKZ> X *pX = new X();
pX->>mf(); // Вот здесь будет AV
NKZ>}
NKZ>
Самое интересно в CGGClass есть виртуальная фукция, кот. переопределена в CMyMegaWnd. Я создаю объект класса CMyMegaWnd, получаю указатель на CGGClass и вызываю эту самую функцию. И она вызывается. Но когда я хочу удалить этот объект при промощи указателя на CGGClass — вылетает ассерт.
Есть способ удалить этот класс не говоря явно тип?
Здравствуйте, <Аноним>, Вы писали:
А>Самое интересно в CGGClass есть виртуальная фукция, кот. переопределена в CMyMegaWnd. Я создаю объект класса CMyMegaWnd, получаю указатель на CGGClass и вызываю эту самую функцию. И она вызывается. Но когда я хочу удалить этот объект при промощи указателя на CGGClass — вылетает ассерт. А>Есть способ удалить этот класс не говоря явно тип?
Этот пример работает корректно, все удаляется. Другое дело если ты пытаешься вызвать виртуальную функцию из CFrameWindowImpl, тогда неопределенное поведение.
Здравствуйте, NKZ, Вы писали:
NKZ>Сам же __declspec(novtable) подавляет генерацию vtable в класcе следовательно ты не можешь вызывать виртуальные функций этого класса из производного.
не совсем так. или совсем не так __declspec(novtable) действительно подавляет генерацию vtable путем удаления кода из конструкторов и деструткора, который инициализирует vptr — указатель на vtbl. Но смысл отключения vtbl совсем в другом — если известно, что экземпляр класса никогда не будет создан, то нет необходимости и в vtbl для этого класса.
Пример, классы для ATL-компонентов, которые генерирует визард, объявляются с ATL_NO_VTABLE, так как реально для класса CX создается экземпляр класса CComObject<CX>( он унаследован от CX ).
Никаких побочных эффектов от использования novtable нет — до тех пор пока не создать экземпляр класса, который объявлен с этим модификатором и вызвать виртуальную функцию.
> Обычно ATL_NO_VTABLE ставят на последний класс в цепочке наследования.
Соотв-но нельзя использовать в последнем классе в цепочке наследования — максимум на предпоследнем
Здравствуйте, Ivan, Вы писали:
I>Здравствуйте, NKZ, Вы писали:
NKZ>>Сам же __declspec(novtable) подавляет генерацию vtable в класcе следовательно ты не можешь вызывать виртуальные функций этого класса из производного.
I>не совсем так. или совсем не так __declspec(novtable) действительно подавляет генерацию vtable путем удаления кода из конструкторов и деструткора, который инициализирует vptr — указатель на vtbl. Но смысл отключения vtbl совсем в другом — если известно, что экземпляр класса никогда не будет создан, то нет необходимости и в vtbl для этого класса.
I>Пример, классы для ATL-компонентов, которые генерирует визард, объявляются с ATL_NO_VTABLE, так как реально для класса CX создается экземпляр класса CComObject<CX>( он унаследован от CX ).
I>Никаких побочных эффектов от использования novtable нет — до тех пор пока не создать экземпляр класса, который объявлен с этим модификатором и вызвать виртуальную функцию.
>> Обычно ATL_NO_VTABLE ставят на последний класс в цепочке наследования. I>Соотв-но нельзя использовать в последнем классе в цепочке наследования — максимум на предпоследнем
Пример кот. вы написали работает.
но пришел домой и пытался исполнить вот такой код:
class CWindowFactory
{
public:
virtual HWND Build(LPVOID pData) = 0;
};
class CEditorFrm2 : public CFrameWindowImpl<CEditorFrm2>, public CWindowFactory
{
public:
DECLARE_FRAME_WND_CLASS_EX(NULL, IDR_EDITORFRAME, 0, COLOR_APPWORKSPACE)
CEditorFrm2() {}
BEGIN_MSG_MAP(CEditorFrm2)
END_MSG_MAP()
virtual BOOL PreTranslateMessage(MSG* pMsg)
{
return FALSE;
}
//CWindowFactory::Build(LPVOID pData);virtual HWND Build(LPVOID pData){return 0;}
};
/// где-то в другой ф-ии
CEditorFrm2* pFrm = new CEditorFrm2();
CWindowFactory* pwf = (CWindowFactory*)(pFrm);
delete pwf; // вот тут вылезает _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); в файле dbgdel.cpp
Здравствуйте, machine1, Вы писали:
M>что такое.. не понимаю.. =((((
не надо забывать о виртуальных деструкторах, если нужно, чтобы delete работал полиморфно
Здравствуйте, Ivan, Вы писали:
I>Здравствуйте, machine1, Вы писали:
M>>что такое.. не понимаю.. =(((( I>не надо забывать о виртуальных деструкторах, если нужно, чтобы delete работал полиморфно
I>