Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8

Шаблоны и функторы как callback для класса свойства объекта. Код работает - но не должен

14.09.2015, 15:39. Показов 1857. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Хочу написать реализацию класса свойства на шаблоне. Т.е есть объект, он инициирует необходимые проперти, в графическом представлении это может быть текстовое поле или combobox, при изменении которого вызывается необходимый функтор. Рабочий код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "stdafx.h"
struct IsEnabled
{
    bool operator()(void) { return true;}
};
struct IsVisible
{
    bool operator()(void) { return true;}
};
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
};
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
};
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
};
template<typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled, typename VisibleFunctor = IsVisible>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
    bool isEnabled()
    {
        return m_enabler();
    }
    bool isVisible()
    {
        return m_visible();
    }
};
class test
{
public:
    test()
    {
    }
    void initProps()
    {
        CProperty<Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>> prop;
        prop.getValue();
        prop.isEnabled();
        prop.isVisible();
        prop.setValue(false);
    }
    
    bool getVal()
    {
        return true;
    }
    void setVal(bool b)
    {
    }
    bool enabler()
    {
        return true;
    }
    bool visible()
    {
        return true;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    test s;
    s.initProps();
    return 0;
}
Как видно свойство опрашивает заданный функтор - getter, setter и т.д, а использование функторов позволяет сделать не всегда необходимые методы проверки свойства - редактируемо, видимо - методами по дефолту. Но, этот код работает, хотя в каждом функторе в дебаге m_sender= 0xCCCCCC - память неинициализированна. Следовательно вызов в функторе, например, Setter - ((*m_sender).*setter)(val); должно приводить к падению. Оптимизация выключена в опциях компилятора. Почему работает?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.09.2015, 15:39
Ответы с готовыми решениями:

Метод класса не работает как callback-функция
Всем привет! Помогите разобраться с синтаксисом. Есть gui-прога, в которой содержится функция TForm4::kau2_2_callback(float value) ...

Libcurl: как должен выглядеть callback?
Прежде, чем юзать libcurl.dll пробовал PyCurl, но тот почему-то все время валит Python. В итоге решил вызывать методы непосредственно из...

Код работает не так как должен
Читаю я значит книгу, а там вот такой код: prompt = &quot;\nTell me something, and I will repeat it back to you:&quot; prompt +=...

8
267 / 170 / 40
Регистрация: 25.08.2014
Сообщений: 1,087
Записей в блоге: 1
14.09.2015, 15:55
Цитата Сообщение от andrew_wk Посмотреть сообщение
Почему работает?
Потому что функции это не данные. Функция есть в файле? Всё что нужно для её вызова есть? Если ответ на оба вопроса утвердительный, то метод будет вызван. Фактически ты обращаешься к информации, получаемой из класса, а не объекта.
0
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8
14.09.2015, 16:03  [ТС]
Пока файл один. Что нужно для ее вызова - здесь немного недогоняю? Но мне кажется, я что-то не так делаю здесь - возможно нужно что-то подправить, чтобы небыло обращения по m_sender, который = 0xCCCCCC ? Можете подсказать?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
14.09.2015, 16:55
Property ???

В языке C++ следует стараться использовать альтернативные приемы, поскольку данный паттерн не является естественным для языка и не может быть реализован полностью в соответствии со своей семантикой.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
14.09.2015, 17:01
Цитата Сообщение от andrew_wk Посмотреть сообщение
Почему работает?
Потому что у тебя нет обращения к данным ClassName. Указатель this передается в холостую и фактически не используется.
Цитата Сообщение от andrew_wk Посмотреть сообщение
Но мне кажется, я что-то не так делаю здесь - возможно нужно что-то подправить, чтобы небыло обращения по m_sender, который = 0xCCCCCC ?
Конечно неправильно. Ты должен по крайней мере инициализировать m_sender в конструкторе.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
 
    Enabler(ClassName * sender) : m_sender(sender) {}
};
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
    
    Getter(ClassName * sender) : m_sender(sender) {}
};
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
 
    Setter(ClassName * sender) : m_sender(sender) {}
};
template<typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled, typename VisibleFunctor = IsVisible>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
    template <typename T>
    CProperty(T * selfPtr) : m_getter(selfPtr), m_setter(selfPtr), m_enabler(selfPtr) 
    {}
 
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
    bool isEnabled()
    {
        return m_enabler();
    }
    bool isVisible()
    {
        return m_visible();
    }
};
 
//.....................
 
    void initProps()
    {
        CProperty<Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>> prop(this);
        prop.getValue();
        prop.isEnabled();
        prop.isVisible();
        prop.setValue(false);
    }
0
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8
14.09.2015, 17:35  [ТС]
Avazart - почти то что я хочу, но функторы позволят явно указывать setter'ы и getter'ы и не только. Меня вообще волнует именно возможность указать переменное число аргументов в
шаблоне.
DrOffset - спасибо! Да я в конструкторе CProperty пробовал инициировать функторы как m_getter(this) и компилятор падал при попытке собрать код.

А вообще, если смотреть взглядом опытного человека - моя реализация имеет право на существование ? Может быть есть "подводные камни", которые я не вижу?

Окончательный вариант:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "stdafx.h"
 
 
//Вызываются по-дефолту, если enabler и/или visible функтор не указаны 
template<typename ClassName>
struct IsEnabled
{
    ClassName *m_sender;
    IsEnabled(ClassName * name):m_sender(name){}
    bool operator()(void) { return true;}
};
 
template<typename ClassName>
struct IsVisible
{
    ClassName *m_sender;
    IsVisible(ClassName * name):m_sender(name){}
    bool operator()(void) { return true;}
};
 
 
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    Enabler(ClassName * name){m_sender = name;}
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
};
 
template<typename ClassName, bool (ClassName::*visible)()>
struct Visible
{
    Visible(ClassName * name):m_sender(name){}
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*visible)();}
};
 
 
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    Getter(ClassName * name):m_sender(name){}
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
};
 
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    Setter(ClassName * name):m_sender(name){}
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
};
 
template<typename ClassName,typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled<ClassName>, typename VisibleFunctor = IsVisible<ClassName>>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
 
    CProperty(ClassName  * obj):m_setter(obj),m_getter(obj),m_enabler(obj),m_visible(obj)
    {
    }
 
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
 
    bool isEnabled()
    {
        return m_enabler();
    }
 
    bool isVisible()
    {
        return m_visible();
    }
};
 
 
 
class test
{
public:
 
    test()
    {
    }
    void initProps()
    {
        CProperty<test,Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>,Visible<test,&test::visible>> *prop = new CProperty<test,Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>,Visible<test,&test::visible>>(this);
        prop->getValue();
        prop->isEnabled();
        prop->isVisible();
        prop->setValue(false);
    }
    
    bool getVal()
    {
        return true;
    }
    void setVal(bool b)
    {
    }
    bool enabler()
    {
        return true;
    }
    bool visible()
    {
        return true;
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    test s;
    s.initProps();
    return 0;
}
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
14.09.2015, 17:49
Цитата Сообщение от andrew_wk Посмотреть сообщение
моя реализация имеет право на существование ?
Да все имеет, пока в продакшен не идет
Ладно - это шутка.
Если серьезно, то предлагаю начать с вариантов использования твоего решения. Напиши себе примеры так, как будто все уже сделано, с точки зрения пользователя. Тогда подводные камни и неудобства сразу будут видны.
Для обучения эта задача вполне подойдет.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
14.09.2015, 18:27
Цитата Сообщение от andrew_wk Посмотреть сообщение
Avazart - почти то что я хочу, но функторы позволят явно указывать setter'ы и getter'ы и не только. Меня вообще волнует именно возможность указать переменное число аргументов в
Нифига не понял из сказанного... каким тут боком функтуры?
0
267 / 170 / 40
Регистрация: 25.08.2014
Сообщений: 1,087
Записей в блоге: 1
14.09.2015, 19:08
Цитата Сообщение от andrew_wk Посмотреть сообщение
Пока файл один.
Исполняемый, я имел ввиду.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
14.09.2015, 19:08
Помогаю со студенческими работами здесь

Этот код должен хранить «hellowor.d» как переменную под названием «Name», но она не работает
public static A = &quot;hello&quot;; public static B = &quot;wor.d&quot;; public static Name = A + B; Этот код должен хранить «hellowor.d» как...

Производный класс Самоорганизующаяся таблица должен наследовать свойства и методы класса Таблица
класс таблица, содержащий целые числа Обьект класса таблица должен позволять: 1 инициализировать случайными числами таблицу 2...

Как задать значение по умолчанию для свойства класса
Где и как можно сохранять и считывать значения свойств класса. Помню - такая возможность есть - но нет книжки под рукой Заранее благодарен

Как отменить свойства только для одной го элемента из класса?
http://rootedinisrael.org/ - создал для пунктов меню навигации нижнее подчеркивание при наведении, но все это распространяется и на...

Один и тот же код на С++ и С#, Шаблоны, отображение содержимого шаблонного класса
написан на С++ шаблонный класс &quot;List&quot; созданный для создания списковой структуры внутри двоичного файла () предусматривается работа с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru