Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> property в c++ 
:(
    Опции темы
Ivan.
Дата 18.8.2011, 19:15 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



Здравствуйте коллеги.
Уже несколько лет я возвращаюсь к мысли как же все таки реализовать проперти в сях. Все время упираюсь во всяческие ограничения компиляторов и т.п. и вот наконец решил, может не самый идеальный вариант, но все же не плохой.

ЗАДАЧА:
Основная задача - это уйти от всяческих конструкторов, дополнительных переменных и максимально оптимизировать код на скорость, объем и удобство применения и вот что у меня получилось:
1. Оптимизация - здесь все отлично, оптимизируется все на этапе компиляции и при работе ни чем не отличается от прямого доступа;
2. Применение - здесь тоже не плохо, можно прикреплять что угодно, хоть к полю родителя, хоть проперти на проперти, да хоть самого на себя зациклить можно;
3. Описание - здесь чуть похуже, но все равно не плохо: 
  а) необходимость прописать класс хозяина или мутатора.
  б) разные дефайны для описания нужного проперти.
  А в остальном не больше чем в настоящем __property;
4. Память - так как мой проперти является структурой, а многие компиляторы описывают пустую структуру минимум в один байт, то каждое проперти будет занимать по 1 байту. Эту проблему я решил описанием всех пропертей в union, то есть в худшем случаи все протепря займут в сумме 1 байт в классе;
5. Ну и наконец сама реализация - всего 15 строчек дефайнов.

КОД:
Код

//---------------------------------------------------------------------------
#define PROPERTY_BEGIN union { struct {} __PROP
#define PROPERTY_PARENT(TObj) (reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
#define PROPERTY_GET( TObj, TVal, Get)    inline      operator TVal()       {return Get(PROPERTY_PARENT(TObj));}
#define PROPERTY_READ(TObj, TVal, Field)  inline      operator TVal()       {return     PROPERTY_PARENT(TObj)->Field;}
#define PROPERTY_SET( TObj, TVal, Set)    inline TVal operator = (TVal Val) {return Set(PROPERTY_PARENT(TObj), Val);}
#define PROPERTY_WRITE(TObj, TVal, Field) inline TVal operator = (TVal Val) {return     PROPERTY_PARENT(TObj)->Field = Val;}
#define PROPERTY_GS(TObj, TVal, Get,  Set)   struct { PROPERTY_GET (TObj, TVal, Get)  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_GW(TObj, TVal, Get,  Write) struct { PROPERTY_GET (TObj, TVal, Get)  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_RS(TObj, TVal, Read, Set)   struct { PROPERTY_READ(TObj, TVal, Read) PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_RW(TObj, TVal, Read, Write) struct { PROPERTY_READ(TObj, TVal, Read) PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_G( TObj, TVal, Get)         struct { PROPERTY_GET (TObj, TVal, Get)                                    }
#define PROPERTY_R( TObj, TVal, Read)        struct { PROPERTY_READ(TObj, TVal, Read)                                   }
#define PROPERTY_S( TObj, TVal,       Set)   struct {                                 PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_W( TObj, TVal,       Write) struct {                                 PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_END }
//---------------------------------------------------------------------------


ОПИСАНИЕ:
PROPERTY_BEGIN - начало блока пропертей.
PROPERTY_END - конец блока пропертей.
Объявление проперти:
PROPERTY_GS - с getter-ом и setter-ом
PROPERTY_GW - с getter-ом и прямым доступом записи в поле
PROPERTY_RS - с прямым доступом чтения поля и setter-ом
PROPERTY_RW - с прямым доступом чтения поля и прямым доступом записи в поле
PROPERTY_G - только с getter-ом
PROPERTY_R - только с прямым доступом на чтение
PROPERTY_S - только с setter-ом
PROPERTY_W - только с прямым доступом на запись
остальные дефайны служебные

ПРИМЕР ПРИМЕНЕНИЯ:
Код

//---------------------------------------------------------------------------
class Tclass1 {
protected:
    int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass1, int, Ffoo, Ffoo) foo;
    PROPERTY_END;
};
class Tclass2 : public Tclass1 {
    int FVal;
    int FArray[2];
    static int GetVal(Tclass2* This)          {return This->FVal;}
    static int SetVal(Tclass2* This, int Val) {return This->FVal = Val;}
public:
    PROPERTY_BEGIN;
        PROPERTY_GS(Tclass2, int, GetVal, SetVal) Val1;
        PROPERTY_RW(Tclass2, int, FVal, FVal) Val2;
        PROPERTY_RS(Tclass2, int, foo, SetVal) Val3;
        PROPERTY_R(Tclass2, int, FArray[0]) Array0;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main()
{
    t.foo = 1;
    t.Val1 = 10;
    t.Val2 = 20;
    t.Val3 = 30;
    PORTB = t.Val1;
    PORTB = t.Val2;
    PORTB = t.Val3;
    PORTB = t.foo;
    PORTB = t.Array0;
}
//---------------------------------------------------------------------------


ВЫВОДЫ:
Как видите привязаться можно к чему угодно, хоть к проперти родителя и оптимизируется на ура.
Если обнаружите ошибки или новые идеи - пишите.

Это сообщение отредактировал(а) Ivan. - 24.8.2011, 16:36


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
boostcoder
Дата 18.8.2011, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



инициатива не должна быть наказуема! поэтому держи пять smile

но давайте лучше посмотрим на препроцессированный код:
Код

class Tclass1 {
protected:
    int Ffoo;
public:

    union {

        struct {
        } __PROP;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass1*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass1*> (1)->__PROP)) + 1))->Ffoo;
            }

            inline int operator =(int Val) {
                return (reinterpret_cast<Tclass1*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass1*> (1)->__PROP)) + 1))->Ffoo = Val;
            }
        } foo;
    };
};

class Tclass2 : public Tclass1 {
    int FVal;
    int FArray[2];

    static int GetVal(Tclass2* This) {
        return This->FVal;
    }

    static int SetVal(Tclass2* This, int Val) {
        return This->FVal = Val;
    }
public:

    union {

        struct {
        } __PROP;

        struct {

            inline operator int() {
                return GetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)));
            }

            inline int operator =(int Val) {
                return SetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)), Val);
            }
        } Val1;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FVal;
            }

            inline int operator =(int Val) {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FVal = Val;
            }
        } Val2;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->foo;
            }

            inline int operator =(int Val) {
                return SetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)), Val);
            }
        } Val3;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FArray[0];
            }
        } Array0;
    };
} t;

int main() {
    Tclass2 t;
    t.foo = 1;
    t.Val1 = 10;
    t.Val2 = 20;
    t.Val3 = 30;
    PORTB = t.Val1;
    PORTB = t.Val2;
    PORTB = t.Val3;
    PORTB = t.foo;
    PORTB = t.Array0;
}


PM WWW   Вверх
Ivan.
Дата 18.8.2011, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



и что в нем не то? ну раскрыл ты дефайны, тебя это пугает? в итоге при компиляции это все сводится к нулю


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
boostcoder
Дата 18.8.2011, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



меня ничего не пугает. смотрю и думаю...
PM WWW   Вверх
mes
Дата 18.8.2011, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Ivan. @  18.8.2011,  18:15 Найти цитируемый пост)
Если обнаружите ошибки

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


Это сообщение отредактировал(а) mes - 18.8.2011, 20:04


--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 18.8.2011, 20:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



хотел проверить, но еще не успел. также нужно сделать проперти [] и закрыть операторы копии


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 19.8.2011, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



Код

//---------------------------------------------------------------------------
class Tclass1 {
protected:
    volatile int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass1, int, Ffoo, Ffoo) foo1;
    PROPERTY_END;
};
//---------------------------------------------------------------------------
class Tclass2 {
protected:
    int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass2, int, Ffoo, Ffoo) foo2;
    PROPERTY_END;
};
//---------------------------------------------------------------------------
class Tclass3 : public Tclass1, public Tclass2 {
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass3, int, foo1, foo1) Val1;
        PROPERTY_RW(Tclass3, int, foo2, foo2) Val2;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main(){
    t.foo1 = 1;
    t.foo2 = 2;
    t.Val1 = 3;
    t.Val2 = 4;
}

Результат:
в Tclass1::Ffoo = 1 (так как переменная volatile)
в Tclass1::Ffoo = 3
в Tclass2::Ffoo = 4
Действие t.foo2 = 2; пропустил за ненадобностью, потому что оно тут же перекроется новыми значениями 4.

Вывод: с множественным наследованием работает прекрасно


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Alca
Дата 19.8.2011, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



А в бусте что нет пропертей?


--------------------
PM WWW ICQ Skype Jabber   Вверх
boostcoder
Дата 19.8.2011, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(Alca @  19.8.2011,  10:40 Найти цитируемый пост)
в бусте что нет пропертей?

нет
PM WWW   Вверх
bsa
Дата 20.8.2011, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Более того, в свое время Борланд пыталась их пропихнуть в стандарт. Но не приняли.
PM   Вверх
Ivan.
Дата 21.8.2011, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



ни как не могу придумать реализацию проперти с индексом.
идея такая:
Код

class Tclass1 {
    int FVal[10];
    static int GetVal(Tclass1* This, int Index) {
        if ((unsigned)Index < (sizeof(FVal) / sizeof(FVal[0]) 
            return This->FVal[Index];
        throw ...;
    }
    struct {
        struct _T {
            inline operator int() {return Tclass1::GetVal(PROPERTY_PARENT(Tclass1), Index); 
        } _Val;
        inline _T& operator [](int Index) {return _Val;}
    } Val;
} t;
int main() {
    PORTB = t.Val[0];
}

остается вопрос, как передать Index?

Это сообщение отредактировал(а) Ivan. - 21.8.2011, 19:19


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 21.8.2011, 20:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Ivan. @  21.8.2011,  18:12 Найти цитируемый пост)
struct _T {
            inline operator int()

может так ?
Код

struct _T {
            inline int operator ()(int index) .. 




--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 21.8.2011, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



интересно, но это уже не проперти, если вместо [] придется использовать (), и все равно не получится реализовать сеттер


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 21.8.2011, 21:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Ivan. @  21.8.2011,  20:16 Найти цитируемый пост)
 если вместо [] придется использовать () 

ну так поставьте оператор [] smile

Добавлено @ 21:20
Цитата(Ivan. @  21.8.2011,  20:16 Найти цитируемый пост)
и все равно не получится реализовать сеттер 

сейчас подумаю..

Добавлено @ 21:24
вам надо возвращать  не ссылку на _Val , а временный прокси-объект хранящий индекс в себе

Это сообщение отредактировал(а) mes - 21.8.2011, 21:24


--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 22.8.2011, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



придумал:
Код

#define PROPERTY_IGET(TVal, Get)    inline      operator TVal()       {return Get(Sender, Index);}
#define PROPERTY_ISET(TVal, Set)    inline TVal operator = (TVal Val) {return Set(Sender, Val, Index);}
#define PROPERTY_K(  TObj)          inline T&   operator [](int Index) {T t = {PROPERTY_PARENT(TObj), Index}; return t;}
#define PROPERTY_I(  TObj)                    struct T {TObj* Sender; int Index;
#define PROPERTY_IGS(TObj, TVal, Get,  Set)   struct { PROPERTY_I() PROPERTY_IGET (TVal, Get)  PROPERTY_ISET (TVal, Set)}; PROPERTY_K(TObj) }
class Tclass3 {
    int FArray[2];
    static int GetArray(Tclass3* This, int Index) {return This->FArray[Index];}
    static int SetArray(Tclass3* This, int Value, int Index) {return This->FArray[Index] = Value;}
public:
    PROPERTY_BEGIN;
        PROPERTY_IGS(Tclass3, int, GetArray, SetArray) Val3;
    PROPERTY_END;
} t;
int main() {
    t.Val3[1] = 10;
    PORTB = t.Val3[1];
}

раскрою дефайны, чтобы было понятней:
Код

class Tclass3 {
    int FArray[2];
    static int GetArray(Tclass3* This, int Index) {return This->FArray[Index];}
    static int SetArray(Tclass3* This, int Value, int Index) {return This->FArray[Index] = Value;}
public:
    union { struct {} __PROP;
        struct {
            struct T {
                Tclass3* Sender; int Index;
                inline     operator int()       {return GetArray(Sender, Index);}
                inline int operator = (int Val) {return SetArray(Sender, Val, Index);}
            };
            inline T& operator [](int Index) {T t = {PROPERTY_PARENT(Tclass3), Index}; return t;}
        } Val3;
    };
} t;
int main() {
    t.Val3[1] = 10;
    PORTB = t.Val3[1];
}

в итоге опять же все оптимизируется на этапе компиляции и ни чем не отличается от прямого вызова мутаторов.

Это сообщение отредактировал(а) Ivan. - 22.8.2011, 11:11


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0730 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.