Re[2]: Не всегда корректный код
От: Аноним  
Дата: 22.06.03 19:23
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

<...>

АТ>Указатель на функцию одного класса в С++ можно приводить к указателю на функцию любого другого класса при помощи 'reinterpret_cast'.



Т.е. это проблемы MSVC, что у него указатель на функцию-член бывает всех размеров — от 4 до 12, и зависит от вируальности функции и наследования ?
Re[3]: Не всегда корректный код
От: Андрей Тарасевич Беларусь  
Дата: 22.06.03 19:39
Оценка:
Здравствуйте, Аноним, Вы писали:

<...>>

АТ>>Указатель на функцию одного класса в С++ можно приводить к указателю на функцию любого другого класса при помощи 'reinterpret_cast'.


А>Т.е. это проблемы MSVC, что у него указатель на функцию-член бывает всех размеров — от 4 до 12, и зависит от вируальности функции и наследования ?


И да, и нет. Разноразмерные указатели у MSVC бывают при умолчатеьных установках проекта: модель указателя на член класса = 'Best case always'. Зайди в установки проекта и явно включи более общую модель указателя на член класса — и все станет в порядке.
Best regards,
Андрей Тарасевич
Re: Обработка событий в С++
От: Viktor Sazhaev  
Дата: 17.07.03 07:18
Оценка:
Здравствуйте.

Идея хорошая. Мне тоже приходили в голову мысли сделать что-то подобное, так что будет что

дополнить. М. б. окажется полезным.

Во-первых, Вы сохраняете и вызываете указатель на функцию-обработчик как указатель на член

структуры slot::Thunk. Это неправильно, потому что не будет работать со множественным

наследованием, также как и в классическом случае с приведением к void*. При множественном

наследовании может требоваться коррекция указателей для вызова методов.

Так что придётся параметризовать класс slot классом Owner, методы которого оттуда

вызываются, либо предпринимать усилия для коррекции указателей вручную — запонминать

смещение и потом его прибавлять/вычитать. Конечно, если не предполагается использовать

механизм вместе со множественным наследованием, то ничего такого делать не нужно. Надо

только предупредить об этом как об ограничении.

В первом случае страшного ничего нет, поскольку один и тот же объект будет использоваться

только с одинм Owner'ом. Здесь возникает единственно потребность сделать общий базовый класс

для наследования под разных Owner'ов и объявить _call() виртуальной.

Во-вторых, по поводу (кажущейся) избыточности. Вам не приходила мысль избавиться от

необходимости хранения в каждом slot'е указателя на Owner'а? Он же его содержит. Я точно не

знаю, возможно ли это, но есть соблазн попробовать вычислять смещение к члену типа slot

внутри Owner'а.

Можно ещё рассмотреть вариант, при котором созданные слоты удалять не нужно, тогда не нужен

двунаправленный список, достаточно однонаправленного. Ещё можно убрать указатели вообще,

добавив в slot указатель на signal, а в signal сохранить массив подцепленных slot'ов. Второе

нам ничего не экономит, лишь позволяет установить обратную связь, которая может пригодиться,

но в обмен на то, что невозможно будет привязать один slot к нескольким signal'ам.

Спасибо.
Re[4]: Не всегда корректный код
От: Viktor Sazhaev  
Дата: 17.07.03 07:31
Оценка:
Не так всё просто. Там же сначала кастуется к указателю на член Thunk, а потом прямо так и вызывается, как метод Thunk. Информация о типе Owner уже потеряна, так что даже для универсального представления указателей вызов теоретически может быть неверным. В любом случае это неправильно — преобразовывать указатели на члены друг в друга. Это борьба с системой типов, которая выходит боком.
Re[5]: Не всегда корректный код
От: Kluev  
Дата: 17.07.03 09:40
Оценка:
Здравствуйте, Viktor Sazhaev, Вы писали:

VS>Не так всё просто. Там же сначала кастуется к указателю на член Thunk, а потом прямо так и вызывается, как метод Thunk. Информация о типе Owner уже потеряна, так что даже для универсального представления указателей вызов теоретически может быть неверным. В любом случае это неправильно — преобразовывать указатели на члены друг в друга. Это борьба с системой типов, которая выходит боком.


Программирования без борьбы не бывает, главное чтобы эта борьба была осознанной. Я почи во всех сових проектах юзаю эту библиотеку и ни разу не прогорел. В реальной жизни в слот передается указатель и функции из одного класса. Согласитесь делать slot в одном классе, а handler в другом (даже в базовом) не есть хороший стиль программирования. Когда slot и handler находтся в одном классе проблем возникнуть не может по определению, независимо от того есть множественное наследование или нет.
Re[6]: Не всегда корректный код
От: yaroslav_v http://yaroslav-v.chat.ru
Дата: 20.07.03 00:44
Оценка:
Если не хочешь верить правильной теории, то вот 2 строчки кода, которые все могут испортить

struct base1 {};
struct base2 {};

struct EventHandler : base1,base2 {
    const char    *color;

    slot    handler; 

    void onEvent( const char *eventName ) {
        printf( "\t%s event handled in %s object\n", eventName, color );
    }

    EventHandler( const char *clr ) : color(clr) {
        handler.init( g_Raiser.event, &EventHandler::onEvent, this );
    }

};


Microsoft (R) 32-bit C/C++ Standard Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
events.cpp
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\sigslot.h(42)
: error C2440: 'type cast' : cannot convert from 'void (__thiscall EventHandler::* )(Arg)' to 'slot::Func'
        with
        [
            Arg=const char *
        ]
        Pointers to members have different representations; cannot cast between them
        events.cpp(32) : see reference to function template instantiation
'void slot::init<EventHandler,const char*>(signal<Arg> &,void (__thiscall EventHandler::* )(Arg),Owner *)' being compiled
        with
        [
            Arg=const char *,
            Owner=EventHandler
        ]

Заметь — это последняя версия компилятора (VS.NET2003), VC6, конечно тоже ругается.
Т.е. указатели на разные классы нельзя преобразовывать друг к другу.
Мозно включить (естественно нестандартную) опцию в MSVC, но тогда пропадет оптимизация,
а это же C++ — тут невидимая, но сильная оптимизация есть одно из основных преимуществ языка.


Да даже если бы можно было — все равно был бы вылет:

У тебя в коде указатель на функцию EventHandler::onEvent (который занимает 16 байт) хранится как указатель на
функцию Thunk::f, который занимает 4 байта — очевидно, что это некорректно.
    struct Thunk {};
    typedef void (Thunk::*Func)();

    Thunk    *_trg;
    Func    _mfn;


Естественно эта проблема решена и давно (см. http://www.boost.org, http://www.rsdn.ru/article/?cpp/delegates.xml
Автор(ы): Александр Шаргин
Дата: 19.03.2003
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.
)
более того у тебя явно зашит тип указателя "Owner*", это естественно не самый лучший метод — например

    void onEvent( const char *eventName ) const


уже не будет компилиться — лечится заменой "Owner*" добавлением нового шаблонного параметра "class OwnerPtrTy" и
заменой "Owner*" на "OwnerPtrTy", это кстати позволит связывать signal не только с обычными указателями, но и со
"smart-pointer'ами", что в современных программах на C++ нужно не редко.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.