Здравствуйте IAZ, вы писали:
IAZ>Здравствуйте VladD2, вы писали:
IAZ>>> И даже тогда остается покрайне мере несколько ситуаций когда они (реализации) будут кардинально не верны. VD>>Т.е. если есть asm-вставка, то обязательно когда ни будь грохнет? А как же половина MS CRT — написанная на asc-е? И куски из ATL?
IAZ>Разве мало случаев когда грохает?
Скажу честно ошибки в ATL и CRT я видел, но чтобы грохало... у меня не разу не случалось.
IAZ>Да, именно, 4 байта. А если указатель на функцию занимает 8 или 12 байт? Тут прямая зависимость от компилятора. Например, возьмет он и оптимизирует код вызова функции, кастрирует к 4 байтам, там где предполагалось 8. А asm вставку он, разумеется, менять не может. И все, полетел asm-вызов.
Ну, 12 это уже фигня, а 8? На, восемь это код расчитан. Главное иметь правильный this. Указатель же все равно будет ровно 4 байта. Это же 32-битный код.
IAZ>При переносе на другую платформу (Ex. I64) программу на C/C++ возможно придется просто перекомпилировать. Ну а на asm’e, сами понимаете, переписать.
"просто перекомпилировать" Ну, ну. Попробуйте на досуге. :) Даже над маленькой будите сидеть часа 3 (если конечно сразу не писать насчитывая на 64-битную переносимость. А asm-ом... да конечно, но его так мало, что по сравнению с другими проблемами...
IAZ>При вызове они соединяются :)
Ага тлько уже поздно :(
IAZ>Я это к тому, что в С и глобальные и статические функции можно приводить к void*, а, соответственно, и друг к другу. А в С++ функция принадлежит классу, а вызов осуществляется при помощи объекта этого класса. Как в стандарте написано, так и реализовано. VC++ в этом случае точна.
Стандарт это бумага, а что в голове у Страуса осталось??? может он просто изложить не сумел? :)
А кто участвовал в проектировании и реализации ATL, MFC, Windows? Черт их знает. Я точно не знаю.
Ну, в MFC люди были знаменитые, но что толку? Слишком тогда была популянрна идея ОО и выращивания всего из одного корня. :)
А авторов ATL я по именам не знаю, но люди точно не ординарные. Красивый код, однако, пишут!
IAZ>Сборка мусора существует с начала появления информатики, как теории. Где она была впервые реализована, навскидку сейчас не вспомню (Algol, PL, LISP?) но точно до 80-х. А указатели на функции он никуда не переносил, какие в С были такие и остались в С++. Было только принято о не возможности приведения функций-членов к void*. Из-за их потенциональной опастности. Многие "недоработки" и "ошибки" С++ происходят из-за не возможности отойти от С на достаточно большое растояние.
"какие в С были такие и остались в С++" НЕ СОГЛАСЕН!!! В С++ идея указателей на функции была УГРОБЛЕНА! Вспомнете как часто испльзуестя callback в C? И подумайте почему он не применяется в C++ (ну, почти).
Что им мешало ввсести возможность создать базовый указатель на функцию любого класса. Ну, 8 байт, ну смещение для класса. Да хоть 16 с this-ом в предачу, но чтобы работать удобно было!
Тут, катати, похожая проблема была с определением размерности и/или инициализированности массивов в VB... Мне дня три (фанаты) докозывали, что это не MS облажался, а КОНЦЕПЦЫЫЫЯ! Ну, и что? Пока спорили MS выпустил бету 1 .Net-а в которой все сделано как я говорил. Так что проблема в том, что есть очень много фанатов которые даже нехотят задумываться над тем, что в их любимой "игрушке" есть недостатки, и в том что сами авторы Ооочень не любят призновать свои ошибки. Ну, что же их понять можно... вот только прощать не хочется. Ведь мучаемся то мы с вами!
IAZ>Особенно посмотрите на концовку. Это чистый callback и даже немного delegate :). Правда приминим только для С++ программ.
Ну, до "delegate" это дело явно не дотягивает. Нужна простая и удобная реализация. Но, кое что возьмем на вооружение.
IAZ>Вам тоже спасибо за интерестный диалог.
И Вам тоже.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
IAZ>>Сборка мусора существует с начала появления информатики, как теории. Где она была впервые реализована, навскидку сейчас не вспомню (Algol, PL, LISP?) но точно до 80-х. А указатели на функции он никуда не переносил, какие в С были такие и остались в С++. Было только принято о не возможности приведения функций-членов к void*. Из-за их потенциональной опастности. Многие "недоработки" и "ошибки" С++ происходят из-за не возможности отойти от С на достаточно большое растояние.
VD>"какие в С были такие и остались в С++" НЕ СОГЛАСЕН!!! В С++ идея указателей на функции была УГРОБЛЕНА! Вспомнете как часто испльзуестя callback в C? И подумайте почему он не применяется в C++ (ну, почти).
Ответ очень прост. Всякий раз, когда С++ программист ловит себя на использовании (попытке использования) callback в границах своего кода, он понимает, что угодил в ловушку C-мышления и прошел мимо какого-то соверешенно естественного design или implementation patterna. Callback тут же летит в мусорное ведро, а на его место становится нормальный человеческий указатель на объект некоторого класса.
Трудно представить себе профессионального С++ программиста, в коде которого даже возникший каким-то образом callback живет более одного-двух дней. Он (callback) ему (программисту) просто спать спокойно не даст.
VD>Что им мешало ввсести возможность создать базовый указатель на функцию любого класса. Ну, 8 байт, ну смещение для класса. Да хоть 16 с this-ом в предачу, но чтобы работать удобно было! VD>Тут, катати, похожая проблема была с определением размерности и/или инициализированности массивов в VB... Мне дня три (фанаты) докозывали, что это не MS облажался, а КОНЦЕПЦЫЫЫЯ! Ну, и что? Пока спорили MS выпустил бету 1 .Net-а в которой все сделано как я говорил. Так что проблема в том, что есть очень много фанатов которые даже нехотят задумываться над тем, что в их любимой "игрушке" есть недостатки, и в том что сами авторы Ооочень не любят призновать свои ошибки. Ну, что же их понять можно... вот только прощать не хочется. Ведь мучаемся то мы с вами!
Это .NET, а не C++. С++ разрабатывался, разрабатывается и будет разрабатываться в соответствии с zero overhead principle. И всякие "композитные" указатели там так же к месту, как команды управления кофемолкой.
И не бывает абсолютных недостатков и абсолютных преимуществ. Все надо рассматривать в контексте. В контексте С++ отсутствие указателей на конкретный метод конкретного экземпляра класса недостатком не является. Тебе такой нужен — возьми и реализуй его сам.
Здравствуйте VladD2, вы писали:
VD>Здравствуйте IAZ, вы писали:
IAZ>>Да, именно, 4 байта. А если указатель на функцию занимает 8 или 12 байт? Тут прямая зависимость от компилятора. Например, возьмет он и оптимизирует код вызова функции, кастрирует к 4 байтам, там где предполагалось 8. А asm вставку он, разумеется, менять не может. И все, полетел asm-вызов.
VD>Ну, 12 это уже фигня, а 8? На, восемь это код расчитан. Главное иметь правильный this. Указатель же все равно будет ровно 4 байта. Это же 32-битный код.
Посмотри размер указателя на f() в такой конструкции:
class A
{
public:
virtual int f(){ return 1; }
};
class B : virtual public A
{
public:
virtual int f(){ return 2; }
};
class C : virtual public A
{
public:
virtual int f(){ return 3; }
};
class D : public B, public C, virtual public A
{
public:
virtual int f(){ return 4; }
void sizef()
{
cout << _T("sizeof(D::B::f())==") << sizeof(&B::f) << endl;
cout << _T("sizeof(D::C::f())==") << sizeof(&C::f) << endl;
cout << _T("sizeof(D::f())==") << sizeof(&D::f) << endl;
}
};
VD>Что им мешало ввсести возможность создать базовый указатель на функцию любого класса. Ну, 8 байт, ну смещение для класса. Да хоть 16 с this-ом в предачу, но чтобы работать удобно было!
Должна быть совместимость с C. Там указатель на функцию в структуре был четыре байта, поэтому в С++ в простейших случаях (одиночное не виртуланое наследование) сделано так-же. А удобство работы иногда конфликтует с эффетивностью.
Здравствуйте VladD2, вы писали:
VD>Здравствуйте Коваленко Дмитрий:
VD>Я тут тоже поизглялся, но результат мне еще не очень нравится. Вызов и инициализация получается красивыми, а вот задание самой функции нет. Так что свой вариант пока не приведу, но Ваш посмотреть очень хочется. То что получилось ... читается очень тяжело. :) Может еще одну попытку? Да через какой нибудь нотпэд?
привет еще раз. я вчера отправил тебе этот файл, но не знаю дошел он или как?
Поэтому еще раз но сюда.
////////////////////////////////////////////////////////////////////////////////
//Классы для хранения указателей на объектные обработчики событий
//Аналог объектных указателей на функции из Builder C++
// Коваленко Дмитрий. 5 мая 2001 года.
#ifndef _t_closure_v1_H_
#define _t_closure_v1_H_
//Структура представленного решения ограничена возможностями BCB3
//
//способ использования:
// 1 определяете тип указателя на объектный обработчик
// typedef t_closure_1<int> t_on_change;
// 2 определяете переменную
// t_on_change on_change;
// 3 устанавливаете обработчик
// on_change=make_closure(&x,TX::handle_change);
// где:
// x — объект класса TX
// TX::handle_change — метод с сигнатурой void handle_change(int);
//
// Вся специфика способа вызова (__stdcall/__fastcall) находиться
// в t_closure_xxx_caller. Поэтому t_closure_xxx зависит только от
// набора аргументов и возвращаемого типа.
//
//как сделать лучше:
// BCB3 не хочет получать указатель на метод в качестве аргумента
// шаблона t_closure1_caller.Если бы это удалось сделать то:
// 1 template<class TObj,class TArg1,void (TObj::*MemFunc)(TArg1)>
// class t_closure1_caller;
// 2 в t_closure_1_caller добавляем статический константный член
// sm_MemFunc=MemFunc и используем его в call в качестве указателя на метод
// 3 в t_closure_1_caller::call не передаем think
// 4 исключаем t_closure_1_caller::think за ненадобностью
namespace structure{
////////////////////////////////////////////////////////////////////////////////
//список классов
//вызов процедур
class t_closure_0;
template<class TA1>
class t_closure_1;
//вызов функций
template<class TResult>
class t_closure_r0;
template<class TResult,class TA1,class TA2>
class t_closure_r2;
template<class TResult,class TA1,class TA2,class TA3,class TA4>
class t_closure_r4;
//__stdcall функции
template<class TResult,class TA1,class TA2>
class t_closure_r2_std;
template<class TResult,class TA1,class TA2,class TA3,class TA4>
class t_closure_r4_std;
////////////////////////////////////////////////////////////////////////////////
//Класс-заглушка для объявления типа __closure_think
namespace closure_v1{ //исключаем его из пространства имен structure
Мама моя родная как я утомился читать эти ветки про адрес метода
господа — переходите на BCB. там есть клевая вещь __closure которая ваше желание с лихвой выполняет. предложенное выше было создано для переноса одной библиотеки на VC. как оказалось зря изголялся — STL на VС6 просто отстой.
А иделогия в этом коде проста до безобразия — с помощью шаблонов генеритуется код длz
1 функции (void*, список аргуметов)
2 классов, которые хранят указатель на объект/указатель на функцию из пункта 1.
но компиляторы с шаблонами просто хреново работают. говорят что BCB5 все чудесно обрабатывает,
но это пока до него не доберешься :)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Ссенькаю! Код прикопал. Будет свободное время и свежая башка разберусь. Думаю по этому вопросу мжно новый поток открывать. :)
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Адрес метода
От:
Аноним
Дата:
20.02.06 09:06
Оценка:
Здравствуйте, Alexander Shargin, Вы писали:
class A
{
int m_a;
...
};
class B;
{
int m_b;
...
};
class C : A, B;
{
int m_c;
...
};
AS>Но теперь функции класса B, которые понятия не имеют о существовании класса C, используют для доступа к члену m_b адрес this+0. Если вызвать функцию класса B для класса C, он будет работать с членом A::m_a по адресу this+0, как будто это B::m_b. Вот почему для обеспечения корректности программы приходится прибавлять смещение к указателю this при использовании функций класса B для объекта C. Поэтому в указателе на функцию для класса C появляется дополнительное поле — смещение. Для любых функций из классов A и C это смещение будет равно нулю, для функций класса B — четырём.