При отключении стандартных библиотек классы в пределах текущей функции (testClass_1::aa в примере ниже) нормально создаются и уничтожаются. С new, delete сложнее – они определены в CRT и непонятно как различать случаи простых переменных и массивов от объектов, требующих вызова конструктора. Но в MSVC 9 оператор new из CRT не использует этого механизма, и собственно даже если бы использовал, всё равно непонятно как вызвать конструктор для «пока несуществующего» класса и передать ему this. Гугл выдал ряд аналогичных вопросов на других форумах так и оставшихся без ответов и единственный более менее внятный пример. Остановился на варианте: Код (Text): #include <windows.h> #pragma comment(linker,"/ENTRY:main") //=============================================== UINT const CF_CREATE_NEW = 0x00000001; //=============================================== class testClass_1 { UINT flags; int a; int b; public: testClass_1(UINT flags = 0); ~testClass_1(); int get_a(void) { return a; }; int get_b(void) { return b; }; }; //------------------------------------------------------- testClass_1::testClass_1(UINT flags) { this->flags = flags; this->a = 0x5; this->b = 0x7; }; //------------------------------------------------------- testClass_1::~testClass_1() { if (this->flags & CF_CREATE_NEW) HeapFree(activeHeap, 0, this); }; //====================================================================================== // Глобальные переменные LPVOID activeHeap; //====================================================================================== // Функция входа в программу int main(void) { activeHeap = GetProcessHeap(); // Объект в пределах функции (флаг не нужен) testClass_1 aa; // заменитель new (указано через флаг вручную) testClass_1 *bb; bb = (testClass_1 *)HeapAlloc(activeHeap, 0, sizeof testClass_1); bb->testClass_1::testClass_1(CF_CREATE_NEW); char outStr[1024]; wsprintf((LPSTR)&outStr, "aa.a = 0x%x, bb.b = 0x%x\nразмер класса = %d", aa.get_a(), bb->get_b(), sizeof testClass_1); MessageBox(NULL, (LPSTR)&outStr, "Мой тест классов", MB_OK); // заменитель delete bb->testClass_1::~testClass_1(); return 0; } где различать способ создания объекта в конструкторе приходится по флагу задаваемому вручную. Совсем без флага не получается определить необходимость HeapFree в деструкторе. Есть ли более изящное решение?
GoldFinch Хотя мысль хорошая - действительно лучше сделать раздельные new_v, new_c, delete_v, delete_c соответственно для переменных и классов и скрыть вызов Heap и конструктора
Код (Text): #include <windows.h> #pragma comment(linker,"/ENTRY:main") //=============================================== UINT const CF_CREATE_NEW = 0x00000001; //=============================================== // Глобальные переменные LPVOID activeHeap; class testClass_1 { int id; int a; int b; public: testClass_1(int _id); ~testClass_1(); int get_a(void) { return a; }; int get_b(void) { return b; }; }; //------------------------------------------------------- testClass_1::testClass_1(int _id) { id = _id; this->a = 0x5; this->b = 0x7; char outStr[1024]; wsprintf((LPSTR)&outStr, "id = 0x%x", id); MessageBox(NULL, (LPSTR)&outStr, "Constructor", MB_OK); }; //------------------------------------------------------- testClass_1::~testClass_1() { char outStr[1024]; wsprintf((LPSTR)&outStr, "id = 0x%x", id); MessageBox(NULL, (LPSTR)&outStr, "Destructor", MB_OK); }; //====================================================================================== inline void* operator new(size_t cb) { return (void*)HeapAlloc(activeHeap, 0, cb); }; inline void operator delete(void* ptr) { HeapFree(activeHeap, 0, ptr); }; // Функция входа в программу int main(void) { activeHeap = GetProcessHeap(); // Объект в пределах функции (флаг не нужен) testClass_1 aa(0xAA); // заменитель new (указано через флаг вручную) testClass_1* bb = new testClass_1(0xBB); char outStr[1024]; wsprintf((LPSTR)&outStr, "aa.a = 0x%x, bb.b = 0x%x\nразмер класса = %d", aa.get_a(), bb->get_b(), sizeof testClass_1); MessageBox(NULL, (LPSTR)&outStr, "Мой тест классов", MB_OK); // заменитель delete delete bb; return 0; } почему не так? *добавил msgbox в конструктор и деструктор
или так Код (Text): class testClass_1 { int id; int a; int b; public: testClass_1(int _id); ~testClass_1(); int get_a(void) { return a; }; int get_b(void) { return b; }; void* operator new(size_t cb) { MessageBox(NULL, "From testClass_1.operator new", NULL, MB_OK); return (void*)HeapAlloc(activeHeap, 0, cb); }; };
GoldFinch Большое спасибо! Не ожидал, что компилятор сам сообразит в этом случае конструктор/деструктор вызвать
Вот что написал комо. Код (Text): "ComeauTest.c", line 10: error: assignment to "this" (anachronism) this = (T*)malloc(sizeof(T)); ^ 1 error detected in the compilation of "ComeauTest.c". In strict mode, with -tused, Compile failed Может лучше закрыть конструкторы и создавать фабрикой? И то что нагородил Страуструп решается с помощью placement new.
Первый раз слышу, чтобы зысу можно было что-то присваивать. Откуда цитата? Может быть какой-нибудь древний стандарт?
Свои классы заработали - красота ) Теперь бы ещё чужие заставить... Код (Text): //================================================================== // Простое тестирование GDI+ #include <windows.h> #include <GdiPlus.h> #pragma comment(linker,"/ENTRY:main") #pragma comment(linker,"/NODEFAULTLIB") // в свойствах линкера: ввод -> дополнительные зависимости -> добавить GdiPlus.lib // #pragma comment(lib, "GdiPlus.lib") при NODEFAULTLIB не работает // Глобальные переменные HINSTANCE hInst; LPVOID activeHeap; using namespace Gdiplus; // Попытка обмануть линковку CRT int _fltused = 0x9875; void drawGDIp(void){ // Подготовительные вычисления int scrW = GetSystemMetrics(SM_CXSCREEN); int scrH = GetSystemMetrics(SM_CYSCREEN); int const rW = 200; int const rH = 200; int rX = (scrW - rW)/2; int rY = (scrH - rH)/2; Graphics graph(GetDC(0)); // graph.Clear(Color(255, 255, 255, 0)); // <- это безобразие работает SolidBrush yellowBrush(Color(255, 255, 255, 0)); // <- не хватает type_info::`vftable' graph.FillRectangle(&yellowBrush, rX, rY, rW, rH); Pen testPen(Color(255, 0, 255, 0), 1.5f); // <- не хватает __fltused graph.DrawLine(&testPen, rX, rY, rX+rW, rY+rH); } // Функция входа в программу int main(void) { // Начальные настройки hInst = GetModuleHandle(NULL); activeHeap = GetProcessHeap(); // Инициализация GDI+. GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // Тестовая отрисовка drawGDIp(); // Завершение программы GdiplusShutdown(gdiplusToken); return 0; } В GDI+ без CRT не хотят создаваться перья и кисти. В исходниках CRT нашёл int _fltused = 0x9875;, но простое добавление этого в свою программу не помогает - как правильно заставить компилятор искать этот символ в моей программе? С vftable похоже сложнее: Конечно можно переписать GdiPlus.h без "лишних констант" и без использования виртуальных функций, которые собственно там совершенно не обязательны, но может есть способ попроще? Наверняка и в других навороченных заголовках есть подобные проблемы.
Y_Mur type_info вообще к RTTI относится. Разве он нужен для GDI+? o_O Это вообще откуда и для чего? Если линкер требует такую переменную, то она наверняка extern "C" должна быть...
maxdiver __fltused хочет иметь Pen testPen(Color(255, 0, 255, 0), 1.5f); extern "C" - спасибо помогло type_info::`vftable' требует линкер для SolidBrush yellowBrush(Color(255, 255, 255, 0)); можно как нибудь глобально запретить GdiPlus.h юзать RTTI? или только детально разбираться - чего они там в этих заголовках наворочали? censored конечно #13 )