|
::Главная страница :: С++/Си :: Статьи |
Свойства С++
Свойства "в стиле VB" невозможно заменить перегрузкой оператора присваивания и приведения типа. Если в классе содержится 10 свойств типа int, мы неизбежно заходим в тупик. Что касается полезности этой концепции, она признана многими разработчиками компонентно-ориентированных средств разработки (кроме VB есть Delphi и BCB, в которые свойства вводились отнюдь не только для поддержки COM, свойства есть в новом языке C# от Микрософт и т. д.). Конечно, свойства - не революция. Вместо них можно использовать пару методов Set/Get. Но они делают смысл происходящего в программе понятнее:
wnd.style |= WS_VISIBLE;
вместо
wnd.SetStyle(wnd.GetStyle() | WS_VISIBLE);
Кроме того, они развивают концепцию сокрытия деталей реализации от пользователя класса: для него свойство выглядит как обычная переменная-член, и он даже не догадывается, что для её реализации используются функции. Не секрет, что многие программисты не любят методы Set/Get и продолжают использовать открытые члены, несмотря на все призывы Страуструпа и иже с ним. Даже в книгах по программированию этот "неправильный" подход встречается сплошь и рядом. Свойства позволяют найти компромисс между этим чисто человеческим нежеланием и важными принципами ООП. В выигрыше оказываются все.
Что касается реализации свойств с С++, здесь перед нами встают проблемы. Если вопрос портирования прграммы для нас не актуален, и мы ограничиваемся VC, я не вижу смысла игнорировать его расширенные возможности. Использование __deсlspec(property) в этом случае является исключительно делом вкуса программиста. Принципиальных возражений против его использования нет.
А вот "самодельные" свойства приносят в жертву эффективность программы, и поэтому мы должны или отказаться от них, или улучшить, убрав лишние затраты. Вот пример возможного улучшения.
#include <stddef.h>
//***************************
// Макрос для свойства
#define PROPERTY(ownertype, proptype, prop, getfunc, setfunc)
\
class __property##prop
\
{
\
public:
\
operator proptype()
\
{
\
return ((ownertype *)((char *)this - offsetof(ownertype,
prop)))->getfunc(); \
}
\
void operator=(proptype data)
\
{
\
((ownertype *)((char *)this - offsetof(ownertype,
prop)))->setfunc(data); \
}
\
};
\
friend __property##prop;
\
__property##prop prop
//***************************
// Пример использования
class CValue
{
private:
char m_value;
public:
int get_Value()
{
return m_value; // Или более сложная логика
}
void put_Value(int value)
{
m_value = value; // Или более сложная логика
}
// Свойство Value типа int, использующее функции
// get_Value и put_Value класса CValue
PROPERTY(CValue, int, Value, get_Value, put_Value);
};
int main(int argc, char* argv[])
{
CValue val;
/*
Здесь вызывается оператор присваивания переменной-члена val.Value,
и, следовательно, функция val.put_Value()
*/
val.Value = 50;
/*
Здесь вызывается оператор приведения типа переменной-члена val.Value,
и, следовательно, функция val.get_Value()
*/
int z = val.Value;
return 0;
}
В этом случае ликвидируются как временные затраты (все функции класса __property##prop
являются встроенными), так и затраты по памяти (к сожалению, только теоретически,
так как VC "не умеет" создавать объекты класса нулевой длины). Кроме
того, следует заметить, что полученное свойство не является полным эквивалентом
__declspec. Например, нельзя написать
val.Value += 50;
Этот недостаток присущ и реализации других программ. Чтобы устранить его, придётся перегружать множество операторов, а потом, возможно, отлавливать множество тонких ошибок. Вот почему я считаю, что "самодельные" свойства представляют скорее теоретический интерес. Это, однако, не повод провозглашать ненужной саму концепцию свойств, аргументируя это мощью и могуществом языка C++, который в них не нуждается.
Тематические
ссылки
|
Ваша ссылка | Ваша ссылка |
Обмен кнопками, ведение статистики, реклама. |
|||