Re[22]: Адрес метода
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.07.01 01:47
Оценка:
Здравствуйте 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>Вам тоже спасибо за интерестный диалог.


И Вам тоже.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[23]: Адрес метода
От: Андрей Тарасевич Беларусь  
Дата: 24.07.01 06:57
Оценка:
Здравствуйте 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. И всякие "композитные" указатели там так же к месту, как команды управления кофемолкой.

И не бывает абсолютных недостатков и абсолютных преимуществ. Все надо рассматривать в контексте. В контексте С++ отсутствие указателей на конкретный метод конкретного экземпляра класса недостатком не является. Тебе такой нужен — возьми и реализуй его сам.

Best regards,
Андрей.
Best regards,
Андрей Тарасевич
Re[23]: Адрес метода
От: IAZ http://iaz.simb.ru
Дата: 24.07.01 17:39
Оценка:
Здравствуйте 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. Там указатель на функцию в структуре был четыре байта, поэтому в С++ в простейших случаях (одиночное не виртуланое наследование) сделано так-же. А удобство работы иногда конфликтует с эффетивностью.

С уважением, IAZ.
Кто ищет то всегда найдет!
Re[24]: Адрес метода
От: IAZ http://iaz.simb.ru
Дата: 24.07.01 17:45
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

Нельзя не согласиться с вами. Замочим Влада :)) (VladD2, не принимай это как вызов)

С уважением, IAZ.
Кто ищет то всегда найдет!
Re[11]: Адрес метода
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 25.07.01 04:50
Оценка:
Здравствуйте 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

struct t_closure_think
{
void f(){;}
void f()const{;}
};

typedef (t_closure_think::*__closure_think)();
};//namespace closure_v1

////////////////////////////////////////////////////////////////////////////////
// КЛАССЫ ДЛЯ УПРАВЛЕНИЯ ОБРАБОТЧИКОМ БЕЗ АРГУМЕНТОВ

template<class TObj>
class t_closure_0_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef void (TObj::*TMemFunc)();

public:
static void call(void* obj,t_think think)
{
assert(obj!=NULL);
assert(think!=NULL);

((*(TObj*)obj).*(*(TMemFunc*)&think))();
}
};

//------------------------------------------------------------------------------
class t_closure_0
{
public: //typedefs
typedef t_closure_0 t_closure;
typedef closure_v1::__closure_think t_think;

//указатель на функцию, занимающуюся вызовом метода
typedef void (*t_caller)(void* obj,t_think);

private:
void* obj;
t_think think;
t_caller caller;

public:
t_closure_0()
:obj(NULL),think(NULL),caller(NULL){;}

t_closure_0(void* obj,t_think _think,t_caller _caller)
:obj(obj),think(_think),caller(_caller){;}

t_closure& operator = (int x)
{
assert(x==0); //только NULL
return *this=t_closure();
}

t_closure& operator = (void* pv)
{
assert(pv==0); //только NULL
return *this=t_closure();
}

void operator () ()const
{
assert(caller!=NULL);
caller(obj,think);
}

operator bool () const
{
return obj!=NULL && think!=NULL && caller!=NULL;
}

bool operator ! () const
{
return !(bool)*this;
}
};//class t_closure_0

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj>
t_closure_0 make_closure(TObj* obj,void (TObj::*MemFunc)())
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_0_caller<TObj> t_caller;
typedef t_closure_0 t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// КЛАССЫ ДЛЯ УПРАВЛЕНИЯ ОБРАБОТЧИКОМ С 1 АРГУМЕНТОМ

template<class TObj,class TA1>
class t_closure_1_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef void (TObj::*TMemFunc)(TA1);

public:
static void call(void* obj,t_think think,TA1 Arg1)
{
assert(obj!=NULL);
assert(think!=NULL);

((*(TObj*)obj).*(*(TMemFunc*)&think))(Arg1);
}
};

//------------------------------------------------------------------------------
template<class TA1>
class t_closure_1
{
public: //typedefs
typedef t_closure_1<TA1> t_closure;
typedef closure_v1::__closure_think t_think;

//указатель на функцию, занимающуюся вызовом метода
typedef void (*t_caller)(void* obj,t_think,TA1);

private:
void* obj;
t_think think;
t_caller caller;

public:
t_closure_1()
:obj(NULL),think(NULL),caller(NULL){;}

t_closure_1(void* obj,t_think _think,t_caller _caller)
:obj(obj),think(_think),caller(_caller){;}

t_closure& operator = (int x)
{
assert(x==0); //только NULL
return *this=t_closure();
}

t_closure& operator = (void* pv)
{
assert(pv==0); //только NULL
return *this=t_closure();
}

void operator () (TA1 arg1)const
{
assert(caller!=NULL);
caller(obj,think,arg1);
}

operator bool () const
{
return obj!=NULL && think!=NULL && caller!=NULL;
}

bool operator ! () const
{
return !(bool)*this;
}
};

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj,class TA1>
t_closure_1<TA1> make_closure(TObj* obj,void (TObj::*MemFunc)(TA1))
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_1_caller<TObj,TA1> t_caller;
typedef t_closure_1<TA1> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// ВЫЗОВ ФУНКЦИИ-ЧЛЕНА БЕЗ АРГУМЕТОВ

template<class TObj,class TResult>
class t_closure_r0_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef TResult (TObj::*TMemFunc)();

public:
static TResult call(void* obj,t_think think)
{
assert(obj!=NULL);
assert(think!=NULL);

return ((*(TObj*)obj).*(*(TMemFunc*)&think))();
}
};

//------------------------------------------------------------------------------
template<class TResult>
class t_closure_r0
{
public: //typedefs
typedef t_closure_r0<TResult> t_closure;
typedef closure_v1::__closure_think t_think;

//указатель на функцию, занимающуюся вызовом метода
typedef TResult (*t_caller)(void* obj,t_think);

private:
void* obj;
t_think think;
t_caller caller;

public:
t_closure_r0()
:obj(NULL),think(NULL),caller(NULL){;}

t_closure_r0(void* obj,t_think _think,t_caller _caller)
:obj(obj),think(_think),caller(_caller){;}

t_closure& operator = (int x)
{
assert(x==0); //только NULL
return *this=t_closure();
}

t_closure& operator = (void* pv)
{
assert(pv==0); //только NULL
return *this=t_closure();
}

TResult operator () ()const
{
assert(caller!=NULL);
return caller(obj,think);
}

operator bool () const
{
return obj!=NULL && think!=NULL && caller!=NULL;
}

bool operator ! () const
{
return !(bool)*this;
}
};//class t_closure_r0

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj,class TResult>
t_closure_r0<TResult> make_closure(TObj* obj,TResult (TObj::*MemFunc)())
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_r0_caller<TObj,TResult> t_caller;
typedef t_closure_r0<TResult> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// ВЫЗОВ ФУНКЦИИ-ЧЛЕНА С 2 АРГУМЕНТАМИ

template<class TObj,class TResult,class TA1,class TA2>
class t_closure_r2_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef TResult (TObj::*TMemFunc)(TA1,TA2);

public:
static TResult call(void* obj,t_think think,TA1 a1,TA2 a2)
{
assert(obj!=NULL);
assert(think!=NULL);

return ((*(TObj*)obj).*(*(TMemFunc*)&think))(a1,a2);
}
};

//------------------------------------------------------------------------------
template<class TResult,class TA1,class TA2>
class t_closure_r2
{
public: //typedefs
typedef t_closure_r2<TResult,TA1,TA2> t_closure;
typedef closure_v1::__closure_think t_think;

//указатель на функцию, занимающуюся вызовом метода
typedef TResult (*t_caller)(void* obj,t_think,TA1,TA2);

private:
void* obj;
t_think think;
t_caller caller;

public:
t_closure_r2()
:obj(NULL),think(NULL),caller(NULL){;}

t_closure_r2(void* obj,t_think _think,t_caller _caller)
:obj(obj),think(_think),caller(_caller){;}

t_closure& operator = (int x)
{
assert(x==0); //только NULL
return *this=t_closure();
}

t_closure& operator = (void* pv)
{
assert(pv==0); //только NULL
return *this=t_closure();
}

TResult operator () (TA1 a1,TA2 a2)const
{
assert(caller!=NULL);
return caller(obj,think,a1,a2);
}

operator bool () const
{
return obj!=NULL && think!=NULL && caller!=NULL;
}

bool operator ! () const
{
return !(bool)*this;
}
};//class t_closure_r2

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj,class TResult,class TA1,class TA2>
t_closure_r2<TResult,TA1,TA2> make_closure(TObj* obj,TResult (TObj::*MemFunc)(TA1,TA2))
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_r2_caller<TObj,TResult,TA1,TA2> t_caller;
typedef t_closure_r2<TResult,TA1,TA2> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// ВЫЗОВ ФУНКЦИИ-ЧЛЕНА С 4 АРГУМЕНТАМИ

template<class TObj,class TResult,class TA1,class TA2,class TA3,class TA4>
class t_closure_r4_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef TResult (TObj::*TMemFunc)(TA1,TA2,TA3,TA4);

public:
static TResult call(void* obj,t_think think,TA1 a1,TA2 a2,TA3 a3,TA4 a4)
{
assert(obj!=NULL);
assert(think!=NULL);

return ((*(TObj*)obj).*(*(TMemFunc*)&think))(a1,a2,a3,a4);
}
};

//------------------------------------------------------------------------------
template<class TResult,class TA1,class TA2,class TA3,class TA4>
class t_closure_r4
{
public: //typedefs
typedef t_closure_r4<TResult,TA1,TA2,TA3,TA4> t_closure;
typedef closure_v1::__closure_think t_think;

//указатель на функцию, занимающуюся вызовом метода
typedef TResult (*t_caller)(void* obj,t_think,TA1,TA2,TA3,TA4);

private:
void* obj;
t_think think;
t_caller caller;

public:
t_closure_r4()
:obj(NULL),think(NULL),caller(NULL){;}

t_closure_r4(void* obj,t_think _think,t_caller _caller)
:obj(obj),think(_think),caller(_caller){;}

t_closure& operator = (int x)
{
assert(x==0); //только NULL
return *this=t_closure();
}

t_closure& operator = (void* pv)
{
assert(pv==0); //только NULL
return *this=t_closure();
}

TResult operator () (TA1 a1,TA2 a2,TA3 a3,TA4 a4)const
{
assert(caller!=NULL);
return caller(obj,think,a1,a2,a3,a4);
}

operator bool () const
{
return obj!=NULL && think!=NULL && caller!=NULL;
}

bool operator ! () const
{
return !(bool)*this;
}
};//class t_closure_r4

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj,class TResult,class TA1,class TA2,class TA3,class TA4>
t_closure_r4<TResult,TA1,TA2,TA3,TA4> make_closure(TObj* obj,TResult (TObj::*MemFunc)(TA1,TA2,TA3,TA4))
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_r4_caller<TObj,TResult,TA1,TA2,TA3,TA4> t_caller;
typedef t_closure_r4<TResult,TA1,TA2,TA3,TA4> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// ВЫЗОВ STDCALL ФУНКЦИИ-ЧЛЕНА С 2 АРГУМЕНТАМИ

template<class TObj,class TResult,class TA1,class TA2>
class t_closure_r2_std_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef TResult __stdcall (TObj::*TMemFunc)(TA1,TA2);

public:
static TResult call(void* obj,t_think think,TA1 a1,TA2 a2)
{
assert(obj!=NULL);
assert(think!=NULL);

return ((*(TObj*)obj).*(*(TMemFunc*)&think))(a1,a2);
}
};

//------------------------------------------------------------------------------
//создание указателя на обработчик
template<class TObj,class TResult,class TA1,class TA2>
t_closure_r2<TResult,TA1,TA2> make_closure(TObj* obj,TResult __stdcall (TObj::*MemFunc)(TA1,TA2))
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_r2_std_caller<TObj,TResult,TA1,TA2> t_caller;
typedef t_closure_r2<TResult,TA1,TA2> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
// ВЫЗОВ STDCALL ФУНКЦИИ-ЧЛЕНА С 4 АРГУМЕНТАМИ

template<class TObj,class TResult,class TA1,class TA2,class TA3,class TA4>
class t_closure_r4_std_caller
{
public: //typedefs
typedef closure_v1::__closure_think t_think;

typedef TResult __stdcall (TObj::*TMemFunc)(TA1,TA2,TA3,TA4);

public:
static TResult call(void* obj,t_think think,TA1 a1,TA2 a2,TA3 a3,TA4 a4)
{
assert(obj!=NULL);
assert(think!=NULL);

return ((*(TObj*)obj).*(*(TMemFunc*)&think))(a1,a2,a3,a4);
}
};

//------------------------------------------------------------------------------
//создание указателя на обработчик

template<class TObj,class TResult,class TA1,class TA2,class TA3,class TA4>
t_closure_r4<TResult,TA1,TA2,TA3,TA4> make_closure_ex(TObj* obj,TResult __stdcall (TObj::*MemFunc)(TA1,TA2,TA3,TA4))
{
typedef closure_v1::__closure_think t_think;
typedef t_closure_r4_std_caller<TObj,TResult,TA1,TA2,TA3,TA4> t_caller;
typedef t_closure_r4<TResult,TA1,TA2,TA3,TA4> t_closure;

return t_closure(obj,*(t_think*)&MemFunc,t_caller::call);
}

////////////////////////////////////////////////////////////////////////////////
};//namespace structure
#endif
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[12]: Адрес метода
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 25.07.01 05:19
Оценка:
Мама моя родная как я утомился читать эти ветки про адрес метода
господа — переходите на BCB. там есть клевая вещь __closure которая ваше желание с лихвой выполняет. предложенное выше было создано для переноса одной библиотеки на VC. как оказалось зря изголялся — STL на VС6 просто отстой.

А иделогия в этом коде проста до безобразия — с помощью шаблонов генеритуется код длz
1 функции (void*, список аргуметов)
2 классов, которые хранят указатель на объект/указатель на функцию из пункта 1.

но компиляторы с шаблонами просто хреново работают. говорят что BCB5 все чудесно обрабатывает,
но это пока до него не доберешься :)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[12]: Адрес метода
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.01 17:03
Оценка:
Здравствуйте Коваленко Дмитрий, вы писали:

Ссенькаю! Код прикопал. Будет свободное время и свежая башка разберусь. Думаю по этому вопросу мжно новый поток открывать. :)
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
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 — четырём.


может класса А?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.