GetInfo.Ru – Компьютерная библиотека
Последние поступления
Как выбрать систему управления базы данных
Базы данных03/09/14
Этапы загрузки UNIX (в схеме)
Unix27/03/12
Gatewall Antispam: тотальный контроль электронной почты
Спам21/04/11
Мастер-класс: создаем Интернет-магазин (Часть 1)
Обзоры ПО20/04/11
CorelDRAW Graphics Suite X5: Что нового?
Обзоры ПО20/07/10
Добавить статью
Самые читаемые материалы
Работа с библиотеками динамической компоновки (DLL)(19548)
Будущие возможности языка программирования C#(14649)
C или C++?(11450)
Интервью Bjarne Stroustrup, данное 1 января 1998 года для журнала Computer(11319)
Модуль для работы с ассоциативными массивами в C++ Builder 5.0(9595)
Всего статей: 793Всего авторов: 364Подразделов: 47Добавлено за сутки: 0
Статьи  СТАТЬИ Форум  ФОРУМ Рейтинг  РЕЙТИНГ Поиск  ПОИСК Контакты  КОНТАКТЫ
» Главная » C/C++ » Модуль для работы с ассоциативными массивами в C++ Builder 5.0

Модуль для работы с ассоциативными массивами в C++ Builder 5.0


Виктор Соколов
kuu@pochta.ru
http://kuu.spb.ru/

Вступление

Мой любимый язык – PHP. Он изящен и прост, но, к сожалению, предназначен только для программирования сайтов. «Обычную» программу на нём не напишешь.

К счастью, некоторые технологии, реализованные в PHP можно перенести и в другие языки программирования: например, в C++.

Одна из таких технологий – ассоциативные массивы.

В ассоциативном массиве вместо числовых индексов используются ключи любых типов. Данные в ассоциативном массиве так же могут быть разнотипными. К примеру:

ass_arr array; 

array[0] = 123;
array["name"] = "John Silver";

Здесь в массиве array создаются два элемента, один из которых имеет ключ «0» и числовое значение «123», другой – ключ «name» и строковое значение «John Silver». «ass_arr» – не массив задниц, как подумало большинство читателей, а возможное имя типа (класса) ассоциативного массива.

Удобно? Удобно! Не нужно описывать входящие в массив элементы и их типы. Не нужно думать о размере массива – он динамичен. Не нужно заботится ни о чём, кроме свободной памяти.

Подробнее об удобствах

Ассоциативный массив – всего лишь способ представления данных. Любая задача, решаемая посредством ассоциативных массивов, может быть решена посредством структур или классов. Однако, использование ассоциативности существенно упрощает решение многих задач.

Рассмотрим простой пример. Возьмём структуру, в которой хранятся настройки некоей программы. Опишем её так:

struct preferences
{ 
int WindowWidth;
int WindowHeight;
int WindowX;
int WindowY;
char documentPath[128];

};

Для сохранения данных этой структуры где-либо, потребуется специальная функция, которая будет «знать» все поля, которые присутствуют в этой структуре. Например, такая:

bool savePreferences(struct preferences* pref)
{ 
saveInteger(pref->WindowWidth);
saveInteger(pref->WindowHeight);
...
saveString(pref->documentPath);

} 

При добавлении в структуру нового поля, придётся дополнять эту функцию.

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

Это могло бы выглядеть так:

bool savePreferences(ass_arr* pref)
{ 
int i;
Variant v; 

// цикл по всем элементам 

for (i = 0; i < pref->Count(); i++)
{ 

// извлекаем очередной элемент 

v = (*pref)[pref->key(i)].v() 

// если элемент числового типа,
// сохраняем его числовое значение 

if (VarType(v) == varInteger)
{ 
saveInteger((*pref)[pref->key(i)].asInteger()); 
} 

// далее для других типов
... 

}

}

Как быть, если нужно заполнить данными настроек Builder'овскую форму? Потребуется ещё одна функция. При использовании ассоциативных массивов эту процедуру можно автоматизировать.

А главное: при добавлении в массив настроек нового поля – не нужно ничего менять.

Существует ещё много подобных задач. Ассоциативные массивы – универсальное средство. Но как реализовать их в C++?

Реализация ассоциативных массивов в C++ Builder

Для реализации класса ассоциативного массива, я использовал несколько стандартных классов: во-первых, Variant – мультитип. В переменной типа Variant может хранится значение любого из стандартных типов. Во-вторых, CList – для создания внутренних списков. Поэтому, вне Builder'а – например, в MSVC++, этот класс работать не будет. Однако, при большом желании, его можно портировать (использовав list из stl и написав свою реализацию Variant).

Моя библиотека содержит три класса: ass_arrEl – класс элемента массива, ass_arr – класс простого ассоциативного массива, и его наследник – prop_ass_arr, предназначенный для работы с окнами настройки. Он «умеет» сохранять и загружать своё содержимое из реестра, заполнять им формы и заполняться содержимым формы сам.

Скачать библиотеку ass_arr 2.0 (3 kb).

Как работать с моими классами

Несколько наглядных примеров:

  • Простой массив. Работа со значениями.
    #include "ass_arr.h"; 
    
    ass_arr a; 
    
    // так можно создать элементы 
    
    a["name"] = "Сажин";
    a["surname"] = "Бесноватый";
    
    
    // а так – обратиться к их значениям 
    
    ShowMessage(a["name"].v());
    ShowMessage(a["name"].v());
    

    a["name"].v() возвращает значение типа Variant.

  • Работа с ключами
    #include "ass_arr.h"; 
    
    ass_arr a;
    int i; 
    
    // Создаём два значения 
    
    a["name"] = "Сажин";
    a["surname"] = "Бесноватый";
    
    
    // Выводим их в цикле 
    
    for (i = 0; i < a.Count(); i++)
    { 
    // a.key(i) возвращает ключ i-го по счёту элемента. 
    // Ключ тоже типа Variant. Заметьте, что при выводе я напрямую
    // не указываю ключей: они определяются автоматически 
    
    ShowMessage(a[a.key(i)].v());
    
    }
    

    В ключах не существует недопустимых символов. Вы можете использовать в качестве ключей даже имена файлов с полными путями!

  • Вложенные массивы. Простейшее дерево.
    #include "ass_arr.h"; 
    
    ass_arr a;
    ass_arr* inner;
    int i; 
    
    // создаём новый ассоциативный массив 
    
    inner = new ass_arr;
    
    
    // заполняем его данными. (*inner)[] - обращение к оператору
    // обьекта по указателю. 
    
    (*inner)["name"] = "Фёдор";
    (*inner)["surname"] = "Сумкин";
    
    
    // вносим его в нулевой элемент массива a 
    
    a[0] = inner; 
    
    inner = new ass_arr;
    (*inner)["name"] = "Фёдор";
    (*inner)["surname"] = "Чистяков";
    a[1] = inner; 
    
    inner = new ass_arr;
    (*inner)["name"] = "Фёдор";
    (*inner)["surname"] = "Беззвестный";
    
    
    // присваивать можно ссылку на массив, либо же сам массив 
    
    a[2] = *inner; 
    
    // теперь выведем поле surname второго элемента 
    
    inner = a[1].sub(); // заносим в inner ссылку на вложенный массив второго элемента
    ShowMessage((*inner)["surname"]); 
    
    // выведем поле name третьего элемента (можно писать так) 
    
    ShowMessage((*(a[2]))["name"]); 
    

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

  • Заполнение формы значениями массива. Загрузка значений ассоциативного массива. Сохранение ассоциативного массива в реестре и загрузка его из реестра.

    Допустим, на форме mainForm два поля: TEdit login и TEdit password. Кроме того, в массиве конфигурации необходимо хранить число запусков программы (numStarts).

    #include "ass_arr.h"; 
    
    prop_ass_arr config;
    
    
    ... mainForm::onCreate(...)
    { 
    // загружаем конфигурацию из реестра 
    
    if (!config.loadSection(HKEY_CURRENT_USER, "Software/Kuu/Passworder"))
    ShowMessage("Не удалось загрузить конфигурацию из реестра");
    
    
    config["numStarts"].v()=config["numStarts"].v()+1;
    
    } 
    
    ... mainForm::onShow(...)
    { 
    // заполняем форму значениями конфигурации 
    
    config.toForm(this); 
    } 
    
    ... mainForm::onDestroy(...)
    { 
    // заполняем конфигурацию значениями из формы 
    
    config.fromForm(this);
    if (!config.saveSection(HKEY_CURRENT_USER, "Software/Kuu/Passworder"))
    ShowMessage("Не удалось сохранить конфигурацию в реестр"); 
    } 
    

    Так просто? Да!

    saveSection и loadSection поддерживают вложенные массивы неограниченного уровня вложенности.

    В настоящий момент функциями toForm() и fromForm() поддерживаются поля только типа TEdit. Если нужно – пишите, сделаю остальные.

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

Используйте на здоровье! Буду рад, если она облегчит жизнь кому-то ещё! При использовании библиотеки ass_arr, обязательна ссылка на сайт автора в документации программы, либо в окне «О программе». Если хотите получать уведомления об обновлениях – напишите мне. Так же, буду благодарен за любые отзывы и комметарии.

Помните: это AS IS. Поэтому, ответственность ни за что я не несу. Однако, в случае внесения изменений (правки ошибок) – присылайте мне исправления.

 
01.04.2004
Версия для печати Версия для печати Запомнить ссылку Запомнить ссылку
Ваша оценка:  1   2   3   4   5     

 О проектеПерепечаткаАвторамПартнерыО нас пишут
Наверх
©2003—2007. GETINFO.RU. ВСЕ ПРАВА ЗАЩИЩЕНЫ.