Понедельник
07-07-2025
12:22


Форма входа

Приветствую Вас Гость | RSS
www.bavlumir.3dn.ru
Главная Каталог статей Регистрация Вход
Главная » Статьи » Языки програмирования » С/С++

Свойства в C++

Немного поигравшись, пришел к реализации свойств в C++, которая обладает некоторыми преимуществами, по сравнению с известными мне реализациями:

  • Свойства не требуют инициализации в конструкторах
  • Независимо от количества свойств, размер класса увеличивается на константу, связанную с выравниваем членов. У меня, например, на 4 байта.

Как это делается?

Реализация свойств

Основные идеи реализации следующие:

  • Шаблон класса свойства не содержит полей! Геттеры и сеттеры передаются в класс в виде шаблонных параметров, о том как извлекается указатель на объект-владелец чуть позже. Эта особенность имеет два важных следствия:
    • Длина класса минимальна, определяется компилятором
    • Можно хранить класс в занятой памяти. То есть, можно создать 100 свойств в одном и том же участке памяти, они не будут перекрываться по данным, потому что данных у них нет.
  • Все классы свойств упаковываются в union, чтобы лежать в одном и том же участке. Именно поэтому размер класса не зависит от количества свойств.
  • Также в этот union добавляется член __properties, используемый для того, что свойства могли определять смещение union относительно начала класса.
  • Зная смещение, каждое свойство определяет адрес объекта-владельца вычитая смещение из собственного адреса. Это вычисление вынесено в отдельный метод в классе properties
  • Чтобы скрыть реализацию, определяются несколько макросов, упрощающих работу с этой структурой.
  • Ниже приведен код, предоставляющий реализацию
/**
 * Класс, предоставляющий общие сервисы для свойств, а также
 * используемый для хранения в классе позиции свойств.
 */
template <
 typename PropertyOwner // Класс владельца
>
class properties {
public:
 // Получить указатель на владельца по указателю на свойство
 static PropertyOwner * owner( void * property ) { 
 int aai = (int)&(((PropertyOwner*)0)->__properties);
 return (PropertyOwner *)((char*)property - aai);
 }
};
 
/**
 * Шаблон класса свойства
 */
template <
 typename PropertyOwner, // Класс владельца
 typename PropertyType, // Тип свойства
 PropertyType (PropertyOwner::*getter)(), // Геттер
 void (PropertyOwner::*setter)(PropertyType) > // Сеттер
class property {
public:
 
 /**
 * Чтение свойства - вызов геттера
 */
 operator PropertyType() {
 return (properties<PropertyOwner>::owner( this )->*getter)();
 }
 
 /**
 * Запись в свойство - вызов сеттера
 */
 void operator = ( const PropertyType & value ) {
 (properties<PropertyOwner>::owner( this )->*setter)( value );
 }
};
 
// Макросы для удобного определения свойств /////////
 
/**
 * Начать объявления свойств в классе cls
 */
#define properties_start(cls) union { properties<cls> __properties;
 
/**
 * Закончить объявление свойств в классе cls
 */
#define properties_end() };
 
/**
 * Объявить свойство в классе cls типа type c геттером getter и сеттером setter
 */
#define property(cls,type,getter,setter) property<cls,type,&cls::getter,&cls::setter>

Использование свойств

Как объявить свойства в классе?

  • Все свойства объявляются в блоке, который начинается вызовом properties_start(<classname>) и заканчивается properties_end().
  • Внутри блока каждое свойство объявляется конструкцией property( cls, type, getter, setter ), аргументы которой - имя класса, тип свойства, имя метода-геттера, имя метода-сеттера.

Вот пример, демонстрирующмй объявление:

class CClass {
private:
 int a_value;
 
 /**
 * Геттер
 */
 int getA() {
 return a_value;
 }
 
 /**
 * Сеттер
 */
 void setA( int a ) {
 a_value = a;
 }
 
public: 
 properties_start( CClass ); // Начало свойств
 
 property( CClass, int, getA, setA ) a; // Свойство
 
 properties_end(); // Конец свойств
};

Использование свойств:

int main( int argc, char ** argv ) {
 CClass c;
 
 c.a = 145; // Запись свойства 
 int aa = c.a; // Чтение свойства
 
 return 0;
}

Ввод и вывод для свойств

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

template <
 typename PropertyOwner,
 typename PropertyType, 
 PropertyType (PropertyOwner::*getter)(),
 void (PropertyOwner::*setter)(PropertyType) >
std::ostream & operator << ( std::ostream & os, property<PropertyOwner,PropertyType,getter,setter> prop ) {
 return os << (PropertyType)prop;
}
 
template <
 typename PropertyOwner,
 typename PropertyType, 
 PropertyType (PropertyOwner::*getter)(),
 void (PropertyOwner::*setter)(PropertyType) >
std::istream & operator >> ( std::istream & is, property<PropertyOwner,PropertyType,getter,setter> prop ) {
 PropertyType value;
 is >> value; 
 prop = value; 
 return is;
}

Ссылки

Категория: С/С++ | Добавил: Ilyxa (11-10-2008)
Просмотров: 756 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
Меню сайта

Категории каталога
[1]
С/С++ [12]
С# [7]
Delphi & Kylix [0]
Java [0]
Java Script [0]
Pascal [0]
Perl [0]
PHP [0]
VB.NET [0]
Visual Basic [0]
Ассемблер ( [0]
Бейсик [0]

Поиск

Друзья сайта

Мини-чат

Наш опрос
Оцените мой сайт
Всего ответов: 13

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Copyright MyCorp © 2025