Здравствуйте Alex Fedotov, вы писали:
AF>Здравствуйте VladD2, вы писали:
VD>>Вот Александр Шаргин дал красивую идею как убрать asm пир копировании указателя на функцию. Может поможете убрать оставшийся asm?
AF>А зачем? Все равно это как было шаманством, так шаманством и останется, полагающимся на реализацию конкретного компилятора.
Думаю, другие компиляторы устроены также. К тому же они мне по барабану. Взяв за основную библиотеку ATL вряд ли будишь задумываться о переносимости. Да, и проблем особых нет! Надо будет, сделаем #if... для нужного компилятора.
AF>Нет, нет и еще раз нет, если мы говорим о языке C++.
Я скорее всего говорю о диалекте этого языка от MS и его реализации в VC. Она пока от стандарта отличается.
AF>В момени инизиализации указателя AF>CPtr ptr = CC::B;
AF>известен только класс, который будет вызываться, а экземпляр класса, может появиться много позже.
Эта и есть никчемная реализация которая меня не устраивает. Да, и плевать мне на то, что Страуструп и орлы из команды VC не додумались до такой простой идеи.
Мне хочется работать легко и писать красивый код! Я уже продемонстрировал, работоспособность такого указателя.
AF>Хорошо известный пример — message maps в MFC, которые хранят указатели на члены класса. А объект появляется гораздо позже, более того, их может быть несколько.
Но мне-то это извращение НЕ НУЖНО! Мне больше нравится реализация в ATL. Она значительно более гибка! Кстати, в ATL есть несколько мест, которые являются извращениями ни чуть не меньшими чем мое... ну и почему все используют ATL и не говорят, что это "не переносимо, шаманство, ...", а? А в Delphi половина базового класса TObject на asm-е написано... Попробуйте сказать Дельфинарию слова про шаманство! :)
AF>Твой же UniversalFuncPtr -- скорее аналог интерфейса, чем указателя на метод класса. Кстати, в реальной жизни, я пользуюсь именно интерфейсами, а не указателями на члены класса.
Он не скорее, а совершенно точно аналогичен указателю на функцию экземпляра в Delphi, Делегату в .Net и т.п. А еще он аналогичен call-back-функции получающей хэндлер, а на интерфейс он совсем не похож (Интерфейс – это указатель на vtbl фиксированного вида). Интерфейсы и я использую, но использовать их для реализации событий (внутри своего кода) — это большой геморрой (Уж с ними мы натрахались вдоволь, в Ax-ах и COM я то точно кое-что понимаю). К тому же у них есть один недостаток – в одном классе, интерфейс нельзя реализовать боле одного раза. Тат же ATL для обхода этого использует примочки в виде базовых классов XxxImpl. Конечно, можно сделать код на базе сообщений Windows, но хочется как то поэлегантней.
AF>Ну, программисты на некоторых других языках (не будем показывать пальцем), считают, что множественное наследование является кривым местом, давайте теперь его исправлять.
Множественное наследование мне нравится, и отказываться от него не хочется (очень жаль, что в .Net на нем поставлен крест). Особенно оно эффективно в сочетании с шаблонами (коих в .Net тоже не наблюдается, но в будущем обещают)...
Раньше я даже не мог понять, почему все новомодные языки стремятся его избежать, а теперь начинаю понимать... Хотя, похоже, всему виной непродуманность, а не реальные проблемы с множественным наследованием.
AF>Я не считаю вызовы функций-членов класса кривыми и я понимаю, почему они реализованы именно так, а не иначе.
А я считаю, что указатели на функции в старом добром C были мощным и удобным инструментом, а указатели на функции-члены в C++ стали совершенно бесполезным хламом. Любое использование этой фичи (которое может прийти мне на ум) можно заменить более изящными средствами (теми же интерфейсами, шаблонами...), а там где это действительно нужно они просто непригодны, из-за "ПРЯПОЙ" реализации. Мне нужно вызывать метод у любого объекта по некоторой ссылке. Именно это и недает мен данная реализация.
MS пытается продать делегаты как свое открытие, тогда как реально их использовали еще на C. И только по вине Страуструпа в C++ не появилось такого же удобного, гибкого и мощного средства как "указатели на функции экземпляра объекта".
PS
Любой язык, претендующий на звание "живого" должен развиваться. Многое, что мы сейчас видим C++ это плод обобщения использования ОО-методов в том самом C. На C чтобы с эмулировать объектную ориентацию приходилось изгаляться не хуже моего. Ну, и что? C++ вобрал в себя все, что мог дать C и привнес несколько фичь которые позволили (более менее) программировать на этом языке как на ОО. Так вот если C++ не хочет уступить место языкам без множественного наследования и других "излишеств" (таким как C# или гы-гы VB.Net) он должен вбирать правильные идеи, а начинаются такие идеи с вот таких извращенческих шаманств. :).
Короче, раньше бы я плюнул, а теперь обязательно это дело на чистых плюсах перепишу. :)
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Аноним, вы писали:
А>Здравствуйте Vovchik, вы писали:
V>>К куче существующих окон необходимо заменить WindowProc. V>>Первое, что пришло в голову, создать класс CMyWnd, V>>содержащий метод MyWndowProc и атрибут OldWindwProc. V>>Одна универсальная функция неэффективна, т.к. единственное V>>различие для вызовов из разных окон это значение hWnd? V>>а по нему искать каждый раз OldWindwProc не хочется.
V>>Вопрос 1: Как заполучить адрес метода из экземпляра класса для SetWindowLong? V>>Вопрос 2: Как иначе организовать множество функций различающихся только V>> значением атрибута OldWindwProc.
А>1. В MFC эта задача решена через глобальную таблицу экземпляров классов окон. А>2. В ATL более красиво, без всяких-там SetWindowLong, — через thunk: А>поищи в сорцах ATL (atlwin.h) все, что связанно с А>struct _WndProcThunk А>{ А> DWORD m_mov; // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd) А> DWORD m_this; // А> BYTE m_jmp; // jmp WndProc А> DWORD m_relproc; // relative jmp А>};
Господа! Хочется задать вопрос!
Так, такие /\/\/\/\ вещи это красИииво или извращЩщщение?! :)
И что лучше без извращений, но с глобальным Мапом, или с извращениями, но коротко и эффективно?
Не стесняйтесь. Высказывайтесь. Интересно любое мнение.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
VD>Здравствуйте Alexander Shargin, вы писали:
VD>Ну, а как на счет замены для вызова функции на asm-е? Я как то пробовал заменить его на вызов в стиле C-декл. (в смысле, глобальной функцией описанной как стандартная сишная ф-я), но что-то у меня не вышло. :( На asm-е получилось проще. :)
Ну, чувствую я, что меня опять назовут извращенцем. :)
На самом деле, чтобы вызвать функцию, достаточно какого-нибудь класса, у которого указатель на функцию "весит" 4 байта. Идеальный кандидат — сам CUniversalFuncPtr. Используя эту идею, вместо
Здравствуйте Alexander Shargin, вы писали:
AS>Ну, чувствую я, что меня опять назовут извращенцем. :)
Не присваивайте чужой славы! Извращенцем называли меня. :)
AS>На самом деле, чтобы вызвать функцию, достаточно какого-нибудь класса, у которого указатель на функцию "весит" 4 байта.
Собственно я так с самого начала думал, но толи не все так просто, толи я лоханулся при создании кода...
AS>Идеальный кандидат — сам CUniversalFuncPtr. Используя эту идею, вместо
AS> int iRetVal; AS> __asm AS> { AS> // Эмулируем thiscall AS> mov ecx, UniversalFuncPtr.pThis; AS> mov eax, UniversalFuncPtr.pF; AS> AS> //push i ; // закладываем значение параметра AS> call eax // ecx.f1(i); AS> mov iRetVal, eax AS> } AS> return iRetVal;
Не очень красиво получается. При таком подходе надо каждый раз создавать новый базовый класс. Надо подумать на счет чего-то более универсальной реализации. Может быть что-то на тех же шаблонах?
А можно ли передавать тип указателя на функцию в качестве параметра шаблона?
PS
Я давно мечтал о человеческой реализации фичи которую теперь называют делегатами.
В любом случае спасибо! И последний вопрос может, создадим статейку на эту тему. Ведь за последнее время эта тема собрало самую большую аудиторию.
К ALL: Если считаете, что такая статья нужна, шлите сюда свои постинги с подтверждением, а так же предложения.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
AS>>На самом деле, чтобы вызвать функцию, достаточно какого-нибудь класса, у которого указатель на функцию "весит" 4 байта. VD>Собственно я так с самого начала думал, но толи не все так просто, толи я лоханулся при создании кода...
Не знаю, там единственная тонкость — приведение (void*&)pfn.
AS>>Идеальный кандидат — сам CUniversalFuncPtr. Используя эту идею, вместо
<skip>
AS>>можно написать:
<skip>
VD>Не очень красиво получается. При таком подходе надо каждый раз создавать новый базовый класс. Надо подумать на счет чего-то более универсальной реализации. Может быть что-то на тех же шаблонах?
Про шаблоны я уже сам занёс руку тебе написать, но вовремя остановился. Дело в том, что, раз уж мы заговорили о делегатах, нам нужна возможность "на лету" заменять указатель на функцию одного объекта указателем на функцию совсем другого. Поэтому придётся оставить всё, как есть.
А новые классы создавать не надо — зачем? Код, который я привёл, эквивалентен твоему ассемблеру: если ты правильно задал this и адрес функции, он будет работать для самых различных объектов... Он ведь просто помещает ptr в ecx и делает call pfn... Хотя это, конечно, извращение... ;)
Александр
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Будет время попробую по-колдовать еще разок. Может выйдет что путное и красивое.
PS
Тут, вот, некоторые говорять извраЩщщение... а некоторые приводят примеры из ATL-ного сабкласинга и говорят красота. Так что — то что для одного изврат, для другого красота. ;)
Еще раз спасибо!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
VD>Так всеже можно тоже самое сделать на сях без asm-а?
Смотря что вы подразумеваете под "темже самым".
А по другому конечно можно :)
структура классов CA, CB, CC таже, повторять нет смысла.
template<class R, class T> class mem_fun_t2
{
typedef R (T::*MFPtr)();
MFPtr pF; // указатель на функцию класса T
public:
explicit mem_fun_t2(MFPtr p) : pF(p) {}
R operator() (T* p) { return (p->*pF)(); } // вызов фунции из конкретного объекта класса T
};
int main(int argc, char* argv[])
{
typedef int (CC::*CPtr)();
CPtr pF= CC::B;
mem_fun_t2<int, CC> fB(pF); // в объекте fB теперь находиться указатель на CC::B
Между прочим, это не я придумал, оригинальный класс mem_fun_t находиться
в файле "functional" из STL.
Можно продолжить идею создания "универсального" указателя на функцию и, в частности, callback. Например, так:
// mem_fun так-же описана в "functional"
template<class R, class T> mem_fun_t2<R,T> mem_fun2(R (T::*f)())
{
return mem_fun_t2<R,T>(f); // всего лишь создаем и возвращаем объект mem_fun_t2
}
// вместо этой функции может быть и класс
template<class R, class Function> R f(Function F)
{
//...
CC c;
R m=F(&c); // F нет в классе СС!
//...
return m;
}
int f2(CC* pC)
{
// все что угодно
//...
return 4;
}
int main(int argc, char* argv[])
{
int m=f<int>(mem_fun2(CC::B)); // вызов CC::B
m=f<int>(f2); // вызов f2
return 0;
}
Здравствуйте VladD2, вы писали:
VD>Но мне-то это извращение НЕ НУЖНО! Мне больше нравится реализация в ATL. Она значительно более гибка! Кстати, в ATL есть несколько мест, которые являются извращениями ни чуть не меньшими чем мое... ну и почему все используют ATL и не говорят, что это "не переносимо, шаманство, ...", а? А в Delphi половина базового класса TObject на asm-е написано... Попробуйте сказать Дельфинарию слова про шаманство! :)
Подобные вещи (использование asm там где можно и без него обойтись) перестауют быдь шаманством только тогда, когда они хорошо протестированы на всех доступных системах и окружениях. И даже тогда остается покрайне мере несколько ситуаций когда они (реализации) будут кардинально не верны.
AF>>Я не считаю вызовы функций-членов класса кривыми и я понимаю, почему они реализованы именно так, а не иначе.
VD>А я считаю, что указатели на функции в старом добром C были мощным и удобным инструментом, а указатели на функции-члены в C++ стали совершенно бесполезным хламом. Любое использование этой фичи (которое может прийти мне на ум) можно заменить более изящными средствами (теми же интерфейсами, шаблонами...), а там где это действительно нужно они просто непригодны, из-за "ПРЯПОЙ" реализации. Мне нужно вызывать метод у любого объекта по некоторой ссылке. Именно это и недает мен данная реализация. VD>MS пытается продать делегаты как свое открытие, тогда как реально их использовали еще на C. И только по вине Страуструпа в C++ не появилось такого же удобного, гибкого и мощного средства как "указатели на функции экземпляра объекта".
Средство "указатели на функции экземпляра объекта" подразумевает две вещи:
1. указатель на объект
2. указатель на функцию в _этом_ объекте
Все это присутствует в С++
Избавивщись от первого мы избавляемся от самого объекта. Так может программировать тогда С? Или использовать глобальные функции, или статические. А может быть по-другому спроектировать программу. Вот ты критикуешь С++ и хвалишь ATL (читай MS) за то что они исправляют "ошибки" Страуструпа. Интерестно какова сложность проектирования C++ и ATL (MFS & etс.)? Где и кем используется С++ и ATL? В конце концов ATL это всего лишь библиотека которую написали как смогли, на том _подмножестве_ C++ которое знали эти программисты и которое поддерживает этот компилятор.
PS: нет такого языка, который бы всем нравился и всех удовлетворял
Здравствуйте VladD2, вы писали:
VD>Здравствуйте Alex Fedotov, вы писали:
AF>>Как компилятор узнает, что p указывает на функцию из класса B, а не из класса A?
VD>Если функция не виртуальная, то ее адрес всегда фиксирован. Адресс функции — это всеголишь адресс ее первой инструкции.
VD>А если так, то смешение может относиться только к сдвизке this (о чем собственно и коворил Шаргин). Структура всех классов известна компилятору и он может добавлять или вычитать смещение сам без доп информации. Так вот, мне и непонятно почему такие плевые операции компилятор не может расчитать сам?
Почему не может? В определенных случаях он даже может виртуальную функцию сделать inline. Но в общем случае пологаться на это нельзя.
Здравствуйте VladD2, вы писали:
VD>В любом случае спасибо! И последний вопрос может, создадим статейку на эту тему. Ведь за последнее время эта тема собрало самую большую аудиторию.
VD>К ALL: Если считаете, что такая статья нужна, шлите сюда свои постинги с подтверждением, а так же предложения.
Сомневаюсь, что такая статья необходима — зачем переливать из пустого в порожнего: так нельзя попробуйте по другому. Это тянет не больше чем на маленький FAQ.
А если все таки написать статью, то неизвестно как она повлияет на неокрепшую психику начинающего программиста. Из-за отсутвия опыта и знаний он может это использовать не поназначению. А чтобы охватить все аспекты этой проблемы одной статьи мало.
Здравствуйте VladD2, вы писали:
VD>Здравствуйте IAZ, вы писали:
IAZ>>Почему не может? В определенных случаях он даже может виртуальную функцию сделать inline. Но в общем случае пологаться на это нельзя.
VD>Гы-гы. ("может"... "пологаться на это нельзя")
VD>PS VD>Вы или не разобрались в вопросе, или не хотите меня пнять.
Очепяток тут хватает, я бы не стал на этом заострять внимание :)
Вопрос был в следующем: присвоить указателю на глобальную функцию указатель на функцию-член. Стандарт это не позваляет. Во многих случаях во время исполнения не происходит добавления этого смещения — добавляется при компиляции. Так что реально такая функция становиться самой обычной (как глобальная). Но еще раз сошлюсь на стандарт: он не позволит обращаться с таким указателем как с обычным. Но asm'е это можно успешно преодалеть, только работать будет не всегда.
Здравствуйте IAZ, вы писали:
IAZ>Подобные вещи (использование asm там где можно и без него обойтись) перестауют быдь шаманством только тогда, когда они хорошо протестированы на всех доступных системах и окружениях.
Ну, "когда они хорошо протестированы на всех доступных системах", это Вы хватили. :)
Кто же даст на свою систему залезть, да и вся жизнь на это уйдет. ;)
Вполне достаточно логического обоснования, ну и может тестирования на компиляторах которые необходимо поддерживать. Для меня – это, пока, VC 6 и VC 7.
IAZ> И даже тогда остается покрайне мере несколько ситуаций когда они (реализации) будут кардинально не верны.
Т.е. если есть asm-вставка, то обязательно когда ни будь грохнет? А как же половина MS CRT — написанная на asc-е? И куски из ATL?
Дело в том, что если есть человеческий метод решения на основном языке, то выпендриваться на asm-е, просто, нет необходимости (если конечно не нужно оптимизировать производительность). Но, не всегда это возможно. Иногда это реальная необходимость (недоработки языка или компилятора), а иногда просто в голову не приходит. :) Вот Шаргин тут давичи показал пример использования шаблона-объединения. Понятно, что вещь стандартная и предусмотренная языком, но вот не пришла она в голову, а на асм-е я там совсем примитивную вещь делал – 4-е байта копировал. Неужели от этого могут быть какие-то проблемы? Да и спецификация thiscall-а полностью описана. Так что проблема здесь может возникнуть, только если первые 4-е байта указателя на функцию класса будут содержать что ни будь отличное от указателя на функцию. В VC такое невозможно, в других компиляторах... возможно конечно, но мало вераятно. Будет возникать проблема с переносимостью разобрались бы с конкретным компилятором и... Ну, а asm здесь вообще не причем напишите такой код хоть на C, хоть на C++, хоть на VB, ровным счетом ни чего не изменится. Здесь налицо зависимость от компилятора.
IAZ>Средство "указатели на функции экземпляра объекта" подразумевает две вещи: IAZ>1. указатель на объект IAZ>2. указатель на функцию в _этом_ объекте
Ага.
IAZ>Все это присутствует в С++
Ага. Но по отдельности. И указатель на функцию одного класса нельзя нормальными средствами преобразовать в указатель на функцию другого объекта. Вот и приходится выходить из положения. Можно конечно воспользоваться указателями на интерфейс (как мне тут советовали), но я уже так ... (почему это неудобно можно почесть из моего ответа тому кто советовал).
IAZ>Избавивщись от первого мы избавляемся от самого объекта. Так может программировать тогда С? Или использовать глобальные функции, или статические.
Причем здесь C и глобальные функции я не знаю, но именно "от первого" и избавился СтраусТруп при создании своих указателей. Может он подразумевал, что указатели на функции разных классов можно будет попросту приводить друг к другу? Я не знаю но реалии жизни, в лице VC, плюют на все предпложения...
IAZ>А может быть по-другому спроектировать программу.
Можно конечно (можно нагородить кучу кода для создания простого алгоритма), а можно и язык по-другому... или небольшой классик/шаблончик нарисовать...
IAZ> Вот ты критикуешь С++ и хвалишь ATL (читай MS) за то что они исправляют "ошибки" Страуструпа.
Страуструпа, да пожалуй, я критикую. Пару тройку правильных решений он не учел.
А "хвалишь ATL" – боже упаси. Я просто заметил, что когда гуру из MS пишут нетривиальный код (иногда использующий asm) для того чтобы потом работать легко и просто, то их называют молодцами, а код называют "красивым". Ну, а если аналогичные действию делают другие, то сразу начинается ханжество (заранее извините, если я кого оскорбил этим словом). Еще раз повторюсь – я с удовольствием переписал бы этот код на чистом C++, но пока красивого законченного решения у меня нет. :(
IAZ> Интерестно какова сложность проектирования C++ и ATL (MFS & etс.)? Где и кем используется С++ и ATL? В конце концов ATL это всего лишь библиотека которую написали как смогли, на том _подмножестве_ C++ которое знали эти программисты и которое поддерживает этот компилятор.
Ннн-да, думаю, что программисты эти были одними из лучших в мире. По крайней мере, нас с Вами они, похоже, превосходят. Так, что можно не сомневаться, что C++ они знают в совершенстве. И не в реализации дело. В VC реализовано (я говорю только о нашей проблеме) то, что было описано в стандарте. Т.е. указатель на некоторую функцию КОНКРЕТНОГО класса! А мне нужен указатель на функцию ЭКЗЕМПЛЯРА объекта. Улавливаете разницу? Так что здесь налицо неграмотное планирование! Планирование элемента языка программирования. Как я уже говорил эту фичу (глубоко наплевав на Дельфи) MS продала за новую идею, назвала ее делегатами, и попыталась встроить ее в Яву. :)
И почему Вы думаете, что "ATL это всего лишь библиотека которую НАПИСАЛИ КАК СМОГЛИ", а C++ это незыблемая вещь которую написали бессмертные гении? Страуструп совсем непохож на Моцарта, да и у последнего не все произведения становились бессмертными. Лажался Страуструп (при создании этого языка) не мало. Так что мы всего лишь замазываем за ним дырки. Не, я понимаю, что многих идей просто не было в то время, например сборки мусора, но указатели на функции он попытался перенести в объектно-ориентированную среду, но … но облажался. Получилась никчемная реализация (из хорошей идеи).
IAZ>PS: нет такого языка, который бы всем нравился и всех удовлетворял
Полностью согласен, но большинство вещей в C++ меня устраивает (недоработок много, но большинство из них можно залатать средствами самого языка). А так... значит если я встретил проблему, то лапки к верху и пошел делать так как получается? Не-ааа, это не для меня. Криво — поправим. Скрипит — подмажем...
А, за Ваш совет (в другом постинге) спасибо. Правда, пока я не разобрался можно ли из него почерпнуть чего интересного, но все равно спасибо!
Будет время, попробую по колдовать. Может и сгодится идея перебивать оператора ().
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте IAZ, вы писали:
IAZ>Здравствуйте VladD2, вы писали:
IAZ>Сомневаюсь, что такая статья необходима — зачем переливать из пустого в порожнего: так нельзя попробуйте по другому. Это тянет не больше чем на маленький FAQ.
Так это зависит от количества написанного? А вопрос этот (в той или другой форме) подымается очень часто. Но все равно спасибо за мнение.
IAZ>А если все таки написать статью, то неизвестно как она повлияет на неокрепшую психику начинающего программиста.
Ну, на психику влиять можно по разному. :) Если хорошенько объяснить, что хорошо, а что плохо, что можно смело использовать, а что с осторожностью... Главный вопрос понимания того, что есть и чего нет! А выводы лучше оставить читателю.
IAZ>Из-за отсутвия опыта и знаний он может это использовать не поназначению.
Ну, батенька — это уже цензура какая-то! Эдак и про нож можно сказать, что его описывать нельзя — "А вдруг его кто не по назначению использует?". :)
IAZ>А чтобы охватить все аспекты этой проблемы одной статьи мало.
А, тут Вы ошибаетесь. Думаю одной статейки будет как раз, а если и не влезет, сделаем сериал. :)
С уважением, Влад.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте IAZ, вы писали:
IAZ>Здравствуйте VladD2, вы писали:
VD>>Здравствуйте IAZ, вы писали:
IAZ>Очепяток тут хватает, я бы не стал на этом заострять внимание :)
Я не об опечатка (сам не без греха). Я о противоречии самому себе в одном обзаце, и о недоверии компилятору. :)
IAZ>Вопрос был в следующем: присвоить указателю на глобальную функцию указатель на функцию-член. Стандарт это не позваляет. Во многих случаях во время исполнения не происходит добавления этого смещения — добавляется при компиляции. Так что реально такая функция становиться самой обычной (как глобальная). Но еще раз сошлюсь на стандарт: он не позволит обращаться с таким указателем как с обычным. Но asm'е это можно успешно преодалеть, только работать будет не всегда.
Не-аа, вопрос был о том, что в С++ не реслизована возможность вызвать фукцию класса по универсальному указателю! Указатель на функцию класса нафих не нужен, а нужен указатель следующего вида:
this // некоторого экземпляра
func_ptr // указатель на функцию
причем если задавать эти параметры во время когда объект создан, то нет проблем ри в вычислении правильного this, ни в вычислении правильного адреса функции (даже если она будет виртуальной). Идея проста как 3 копейки но увы...
А вызов он хоть будь трижды виртуальным все равно вревратится в:
f1(this, xxx);
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
IAZ>> И даже тогда остается покрайне мере несколько ситуаций когда они (реализации) будут кардинально не верны. VD>Т.е. если есть asm-вставка, то обязательно когда ни будь грохнет? А как же половина MS CRT — написанная на asc-е? И куски из ATL?
Разве мало случаев когда грохает?
VD><skip> а на асм-е я там совсем примитивную вещь делал – 4-е байта копировал. Неужели от этого могут быть какие-то проблемы? Да и спецификация thiscall-а полностью описана. Так что проблема здесь может возникнуть, только если первые 4-е байта указателя на функцию класса будут содержать что ни будь отличное от указателя на функцию.
Да, именно, 4 байта. А если указатель на функцию занимает 8 или 12 байт? Тут прямая зависимость от компилятора. Например, возьмет он и оптимизирует код вызова функции, кастрирует к 4 байтам, там где предполагалось 8. А asm вставку он, разумеется, менять не может. И все, полетел asm-вызов.
VD>Будет возникать проблема с переносимостью разобрались бы с конкретным компилятором и... Ну, а asm здесь вообще не причем напишите такой код хоть на C, хоть на C++, хоть на VB, ровным счетом ни чего не изменится. Здесь налицо зависимость от компилятора.
При переносе на другую платформу (Ex. I64) программу на C/C++ возможно придется просто перекомпилировать. Ну а на asm’e, сами понимаете, переписать.
IAZ>>Средство "указатели на функции экземпляра объекта" подразумевает две вещи: IAZ>>1. указатель на объект IAZ>>2. указатель на функцию в _этом_ объекте IAZ>>Все это присутствует в С++
VD>Ага. Но по отдельности. И указатель на функцию одного класса нельзя нормальными средствами преобразовать в указатель на функцию другого объекта.
При вызове они соединяются :)
IAZ>>Избавивщись от первого мы избавляемся от самого объекта. Так может программировать тогда С? Или использовать глобальные функции, или статические.
VD>Причем здесь C и глобальные функции я не знаю, но именно "от первого" и избавился СтраусТруп при создании своих указателей. Может он подразумевал, что указатели на функции разных классов можно будет попросту приводить друг к другу? Я не знаю но реалии жизни, в лице VC, плюют на все предпложения...
Я это к тому, что в С и глобальные и статические функции можно приводить к void*, а, соответственно, и друг к другу. А в С++ функция принадлежит классу, а вызов осуществляется при помощи объекта этого класса. Как в стандарте написано, так и реализовано. VC++ в этом случае точна.
IAZ>> Интерестно какова сложность проектирования C++ и ATL (MFS & etс.)? Где и кем используется С++ и ATL? В конце концов ATL это всего лишь библиотека которую написали как смогли, на том _подмножестве_ C++ которое знали эти программисты и которое поддерживает этот компилятор.
VD>Ннн-да, думаю, что программисты эти были одними из лучших в мире. По крайней мере, нас с Вами они, похоже, превосходят. Так, что можно не сомневаться, что C++ они знают в совершенстве. И не в реализации дело.
<skip> VD>И почему Вы думаете, что "ATL это всего лишь библиотека которую НАПИСАЛИ КАК СМОГЛИ", а C++ это незыблемая вещь которую написали бессмертные гении? Страуструп совсем непохож на Моцарта, да и у последнего не все произведения становились бессмертными. Лажался Страуструп (при создании этого языка) не мало. Так что мы всего лишь замазываем за ним дырки. Не, я понимаю, что многих идей просто не было в то время, например сборки мусора, но указатели на функции он попытался перенести в объектно-ориентированную среду, но … но облажался. Получилась никчемная реализация (из хорошей идеи).
Да я и не говорил что C++ это незыблемая вещь которую написали бессмертные гении. Но С++ разрабатывается (он продолжает развиваться) с 1983 года. Причем группой очень умных людей. Помимо Страуструпа, интеллектуальный уровень которого мы объективно не сможем оценить, но достаточно того что он задумал этот язык, там есть и Керниган и Ричи и Кениг, т.е. те кто приложил руку :) к созданию С и Unix. А кто участвовал в проектировании и реализации ATL, MFC, Windows? Черт их знает. Я точно не знаю.
Сборка мусора существует с начала появления информатики, как теории. Где она была впервые реализована, навскидку сейчас не вспомню (Algol, PL, LISP?) но точно до 80-х. А указатели на функции он никуда не переносил, какие в С были такие и остались в С++. Было только принято о не возможности приведения функций-членов к void*. Из-за их потенциональной опастности. Многие "недоработки" и "ошибки" С++ происходят из-за не возможности отойти от С на достаточно большое растояние.
VD>А, за Ваш совет (в другом постинге) спасибо. Правда, пока я не разобрался можно ли из него почерпнуть чего интересного, но все равно спасибо! VD>Будет время, попробую по колдовать. Может и сгодится идея перебивать оператора ().
Особенно посмотрите на концовку. Это чистый callback и даже немного delegate :). Правда приминим только для С++ программ.
Вам тоже спасибо за интерестный диалог.
С уважением, IAZ.
Здравствуйте VladD2, вы писали:
VD>Здравствуйте IAZ, вы писали:
IAZ>>Сомневаюсь, что такая статья необходима — зачем переливать из пустого в порожнего: так нельзя попробуйте по другому. Это тянет не больше чем на маленький FAQ.
VD>Так это зависит от количества написанного?
Зависит :)
IAZ>>Из-за отсутвия опыта и знаний он может это использовать не поназначению.
VD>Ну, батенька — это уже цензура какая-то! Эдак и про нож можно сказать, что его описывать нельзя — "А вдруг его кто не по назначению использует?". :)
IAZ>>А чтобы охватить все аспекты этой проблемы одной статьи мало.
У меня было два предложения но записанные в одну строку :) Поскольку программер неопытный ему надо представить проблему как можно шире. Я согласен: пусть сам решает.
VD>А, тут Вы ошибаетесь. Думаю одной статейки будет как раз, а если и не влезет, сделаем сериал. :)
VD>С уважением, Влад.
Я тут тоже поизглялся, но результат мне еще не очень нравится. Вызов и инициализация получается красивыми, а вот задание самой функции нет. Так что свой вариант пока не приведу, но Ваш посмотреть очень хочется. То что получилось ... читается очень тяжело. :) Может еще одну попытку? Да через какой нибудь нотпэд?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.