m_owner(owner), m_getter(getmethod), m_setter(setmethod) {}
// Инициализация
void init(propowner * const owner, getter getmethod, setter setmethod) {
m_owner = owner;
m_getter = getmethod;
m_setter = setmethod;
}
};
Теперь класс, реализующий свойство можно написать так:
class CValue {
private:
int m_value;
int get_Value() {
return m_value; // Или более сложная логика
}
void put_Value(int value) {
m_value = value; // Или более сложная логика
}
public:
property Value;
CValue() {
Value.init(this, get_Value, put_Value);
}
};
А вот код, использующий этот класс:
CValue val;
/*
Здесь вызывается оператор присваивания переменной-члена val.Value, и, следовательно, функция val.put_Value()
*/
val.Value = 50;
/*
Здесь вызывается оператор приведения типа переменной-члена val.Value, и, следовательно, функция val.get_Value()
*/
int z = va.Value;
Как можно видеть, получились "настоящие" свойства средствами только стандартного синтаксиса C++. Однако, описанный метод не лишен недостатков:
• При каждом обращении к "свойству" происходит два вызова функции.
• Использование таких "свойств" требует дополнительных затрат памяти из-за того, что на каждое "свойство" требуется 3 дополнительных указателя, что составляет 12 байт накладных расходов.
• Использование шаблонов приводит к увеличению размеров исполняемого кода, поскольку компилятор будет генерировать отдельный класс для каждой пары "proptype" и "propowner".
• Для каждого "свойства" необходимо не забыть произвести инициализацию в конструкторе класса-владельца.
ВОПРОС-ОТВЕТ
Как научить программу реагировать на изменение содержимого буфера обмена?
Автор: Александр Шаргин Версия текста: 1.0 Программа-пример CbView Программа-пример MfcCbView
В Windows существует понятие наблюдателя за буфером обмена (clipboard viewer), которым может стать любое окно. Наблюдатель получает от системы уведомления об изменении содержимого буфера обмена в виде сообщения WM_DRAWCLIPBOARD. Соответственно, в ответ на это сообщение программа может загрузить содержимое буфера обмена и выполнить с ним нужные операции (типичный пример – отобразить содержимое буфера обмена в окне).
Интересен способ взаимодействия системы с несколькими наблюдателями за буфером обмена. Дело в том, что с точки зрения Windows наблюдатель всегда один (он называется текущим), и только ему посылаются уведомления. Передача этих уведомлений дальше по цепочке наблюдаетей – задача приложения. Для этого каждая программа, регистрирующая наблюдателя за буфером обмена, получает и сохраняет в переменной HWND предыдущего наблюдателя, а затем передаёт ему сообщения с помощью одной из функций SendMessage, PostMessage и т.п. "Недобросовестная" программа, которая не передаёт уведомления дальше по цепочке, может нарушить работу других приложений и даже других экземпляров самой себя, поэтому писать такие программы настоятельно не рекомендуется.
Рассмотрим процесс работы программы-наблюдателя более подробно. Первое, что ей необходимо сделать – это зарегистрировать своё окно при помощи функции SetClipboardViewer, которая возвращает хэндл текущего наблюдателя и делает текущим наше окно. Как уже говорилось, переданный нам хэндл окна следует сохранить в переменной для дальнейшего использования. Например:
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
…
static HWND hNextViewer;
…
hNextViewer = SetClipboardViewer(hDlg);
…
}
Следующий шаг – научить программу реагировать на сообщение WM_DRAWCLIPBOARD. Это очень простое сообщение, никак не использующее параметры wParam и lParam. Как я уже говорил, программа обязана передать это сообщение дальше по цепочке наблюдателей. Выглядит это так.
case WM_DRAWCLIPBOARD:
// Работаем с буфером обмена
if(IsWindow(hNextViewer)) PostMessage(hNextViewer, msg, wParam, lParam);
ПРИМЕЧАНИЕ
В общем случае весьма опасно использовать SendMessage для отправки сообщений чужим окнам. Если приложение, которому принадлежит окно, занято выполнением длительной операции или же просто "зависло" в бесконечном цикле, то в ожидании возврата из SendMessage наше приложение зависнет тоже. Вот почему лучше использовать PostMessage, как это сделано в примере выше, или воспользоваться функциями типа SendMessageTimeout.
Не менее важно правильно удалить себя из очереди наблюдателей за буфером обмена. Для этого используется функция ChangeClipboardChain, которая получает в качестве параметров хэндлы нашего окна и следующего наблюдателя в цепочке, которому мы передаём уведомления. Например:
Читать дальше