ATL_NO_VTABLE и все такое..
От: machine1 Россия  
Дата: 10.11.04 19:47
Оценка:
Добрый день!

Представьте себе вот что: есть окно CMyMegaWnd, наследованное от CFrameWindowImpl, кот. объявлен с ATL_NO_VTABLE и от некоторого класса CGGClass.
А можно ли имея казатель на CGGClass удалить весь объект CMyMegaWnd??

Спасибо.
:: machine1
Re: ATL_NO_VTABLE и все такое..
От: NKZ  
Дата: 11.11.04 08:31
Оценка:
Здравствуйте, machine1, Вы писали:

M>Представьте себе вот что: есть окно CMyMegaWnd, наследованное от CFrameWindowImpl, кот. объявлен с ATL_NO_VTABLE и от некоторого класса CGGClass.

M>А можно ли имея казатель на CGGClass удалить весь объект CMyMegaWnd??

Определение макроса ATL_NO_VTABLE следующее:

#ifdef _ATL_DISABLE_NO_VTABLE
   #define ATL_NO_VTABLE
#else
   #define ATL_NO_VTABLE __declspec(novtable)
#endif


Сам же __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>#ifdef _ATL_DISABLE_NO_VTABLE
NKZ>   #define ATL_NO_VTABLE
NKZ>#else
NKZ>   #define ATL_NO_VTABLE __declspec(novtable)
NKZ>#endif
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 — вылетает ассерт.
Есть способ удалить этот класс не говоря явно тип?
Re[3]: ATL_NO_VTABLE и все такое..
От: NKZ  
Дата: 11.11.04 11:02
Оценка: 2 (1)
Здравствуйте, <Аноним>, Вы писали:

А>Самое интересно в CGGClass есть виртуальная фукция, кот. переопределена в CMyMegaWnd. Я создаю объект класса CMyMegaWnd, получаю указатель на CGGClass и вызываю эту самую функцию. И она вызывается. Но когда я хочу удалить этот объект при промощи указателя на CGGClass — вылетает ассерт.

А>Есть способ удалить этот класс не говоря явно тип?

Этот пример работает корректно, все удаляется. Другое дело если ты пытаешься вызвать виртуальную функцию из CFrameWindowImpl, тогда неопределенное поведение.

#pragma once 
#include <iostream>

using namespace std;

class __declspec(novtable) CFrameWindowImpl
{
public:
    CFrameWindowImpl()
    {
        cout << "Ctor CFrameWindowImpl\n";
    }
    virtual ~CFrameWindowImpl()
    {
        cout << "Dtor CFrameWindowImpl\n";
    }
    virtual void TestFunc()
    {
        cout << "CFrameWindowImpl::TestFunc\n";
    };
};

class CGGClass
{
public:
    CGGClass()
    {
        cout << "Ctor CGGClass\n";
    }
    virtual ~CGGClass()
    {
        cout << "Dtor CGGClass\n";
    }
    virtual void TestFunc()
    {
        cout << "CGGClass::TestFunc\n";
    } 
};

class CMyMegaWnd : public CFrameWindowImpl,
    public CGGClass
{
public:
    CMyMegaWnd()
    {
        cout << "Ctor CMyMegaWnd\n";
    };
    ~CMyMegaWnd()
    {
        cout << "Dtor CMyMegaWnd\n";
    };
    virtual void TestFunc()
    {
        cout << "CMyMegaWnd::TestFunc\n";
    } 
};

void Test()
{
    CMyMegaWnd* pMyMegaWnd = new CMyMegaWnd();
    CGGClass* pCGGClass = dynamic_cast<CGGClass*>(pMyMegaWnd);    
    delete pCGGClass;
}
... << RSDN@Home 1.1.4 beta 3 rev. 0>>
Re[4]: ATL_NO_VTABLE и все такое..
От: machine1 Россия  
Дата: 11.11.04 11:12
Оценка:
Спасибо..

значит падает по другой причине..
будем разбираться.
:: machine1
Re[2]: ATL_NO_VTABLE и все такое..
От: Ivan Россия www.rsdn.ru
Дата: 11.11.04 15:33
Оценка: 4 (1)
Здравствуйте, 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 ставят на последний класс в цепочке наследования.

Соотв-но нельзя использовать в последнем классе в цепочке наследования — максимум на предпоследнем
Re[3]: ATL_NO_VTABLE и все такое..
От: machine1 Россия  
Дата: 11.11.04 16:08
Оценка:
Здравствуйте, 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
Re[4]: ATL_NO_VTABLE и все такое..
От: Ivan Россия www.rsdn.ru
Дата: 11.11.04 16:38
Оценка: 2 (1)
Здравствуйте, machine1, Вы писали:

M>что такое.. не понимаю.. =((((

не надо забывать о виртуальных деструкторах, если нужно, чтобы delete работал полиморфно

class CWindowFactory
{
public:
    virtual HWND Build(LPVOID pData) = 0;
    virtual ~CWindowFactory() {} /* = 0 */ ;
};
Re[5]: ATL_NO_VTABLE и все такое..
От: machine1 Россия  
Дата: 11.11.04 16:51
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, machine1, Вы писали:


M>>что такое.. не понимаю.. =((((

I>не надо забывать о виртуальных деструкторах, если нужно, чтобы delete работал полиморфно

I>
I>class CWindowFactory
I>{
I>public:
I>    virtual HWND Build(LPVOID pData) = 0;
I>    virtual ~CWindowFactory() {} /* = 0 */ ;
I>};
I>



Ой я балда совсем забыл.
спасибо.
:: machine1
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.