Практическое руководство. Создание типобезопасных коллекций
В этой статье объясняется, как создавать типобезопасные коллекции для собственных типов данных. Разделы включают:
Библиотека классов Microsoft Foundation предоставляет предопределенные типобезопасные коллекции на основе шаблонов C++ . Так как они являются шаблонами, эти классы помогают обеспечить безопасность типов и простоту использования без приведения типов и других дополнительных работ, связанных с использованием класса nontemplate для этой цели. В примере MFC COLLECT демонстрируется использование классов коллекций на основе шаблонов в приложении MFC. Как правило, используйте эти классы в любой момент, когда вы пишете новый код коллекций.
Использование классов на основе шаблонов для типа Сейф ty
Использование классов на основе шаблонов
Объявите переменную типа класса коллекции. Например:
CList<int, int> m_intList;
Вызовите функции-члены объекта коллекции. Например:
m_intList.AddTail(100); m_intList.RemoveAll();
При необходимости реализуйте вспомогательные функции и SerializeElements. Сведения о реализации этих функций см. в разделе "Реализация вспомогательных функций".
В этом примере показано объявление списка целых чисел. Первый параметр на шаге 1 — это тип данных, хранящихся в виде элементов списка. Второй параметр указывает, как данные передаются и возвращаются из функций-членов класса коллекции, таких как Add
и GetAt
.
Реализация вспомогательных функций
Классы коллекций на основе шаблонов CArray
CList
и CMap
пять глобальных вспомогательных функций, которые можно настроить по мере необходимости для производного класса коллекции. Дополнительные сведения об этих вспомогательных функциях см. в справке по классам коллекций в справочнике по MFC. Реализация функции сериализации необходима для большинства классов коллекций на основе шаблонов.
Сериализация элементов
CList
CMap
Вызов CArray
и классы SerializeElements
для хранения элементов коллекции в архив или их чтения из архива.
Реализация вспомогательной SerializeElements
функции по умолчанию выполняет побитовую запись из объектов в архив или побитовое чтение из архива в объекты в зависимости от того, хранятся ли объекты в архиве или извлекаются из архива. Переопределите SerializeElements
, если это действие не подходит.
Если коллекция хранит объекты, производные от CObject
этого, и вы используете макрос в реализации класса элементов коллекции, вы можете воспользоваться IMPLEMENT_SERIAL
преимуществами функций сериализации, встроенных в CArchive
и CObject
:
CArray< CPerson, CPerson& > personArray;
template <> void AFXAPI SerializeElements <CPerson>(CArchive& ar,
CPerson* pNewPersons, INT_PTR nCount)
{
for (int i = 0; i < nCount; i++, pNewPersons++)
{
// Serialize each CPerson object
pNewPersons->Serialize(ar);
}
}
Перегруженные операторы вставки для CArchive
вызова CObject::Serialize
(или переопределения этой функции) для каждого CPerson
объекта.
Использование классов коллекции Nontemplate
MFC также поддерживает классы коллекций, представленные в MFC версии 1.0. Эти классы не основаны на шаблонах. Их можно использовать для хранения данных поддерживаемых типов CObject*
, UINT
DWORD
и CString
. Эти стандартные коллекции (например CObList
) можно использовать для хранения коллекций любых объектов, производных от CObject
. MFC также предоставляет другие предопределенные коллекции для хранения примитивных типов, таких как UINT
и указатели void (void*
). В общем случае часто бывает полезно определить собственные коллекции, безопасные для типа, для хранения объектов более конкретного класса и его производных. Обратите внимание, что это делается с классами коллекции, не основанными на шаблонах, является более работой, чем использование классов на основе шаблонов.
Существует два способа создания типобезопасных коллекций с коллекциями nontemplate:
При необходимости используйте коллекции nontemplate с приведением типов. Это более простой подход.
Производный от и расширяющий типобезопасную коллекцию, не относясь к типу.
Использование коллекций nontemplate с приведением типов
Используйте один из нетемплатных классов, например
CWordArray
напрямую.Например, можно создать
CWordArray
и добавить в него 32-разрядные значения, а затем получить их. Больше ничего не делать. Вы просто используете предопределенные функции.Можно также использовать предопределенную коллекцию, например
CObList
для хранения любых объектов, производных отCObject
. КоллекцияCObList
определяется для хранения указателейCObject
на . При получении объекта из списка может потребоваться привести результат к соответствующему типу, так какCObList
функции возвращают указателиCObject
на . Например, если вы хранитеCPerson
объекты вCObList
коллекции, необходимо привести извлеченный элемент, чтобы быть указателем наCPerson
объект. В следующем примере для храненияCPerson
объектов используетсяCObList
коллекция:CPerson* p1 = new CPerson(); CObList myList; myList.AddHead(p1); // No cast needed CPerson* p2 = (CPerson*)myList.GetHead();
Этот метод использования предопределенного типа коллекции и приведения, как это необходимо, может быть достаточно для многих потребностей вашей коллекции. Если вам нужна дополнительная функциональность или более безопасность типов, используйте класс на основе шаблона или выполните следующую процедуру.
Наследование и расширение небезопасной коллекции типов
Наследуйте собственный класс коллекции из одного из предопределенных классов, не являющихсяtemplate.
При наследовав класс, можно добавить функции-оболочки, безопасные для типа, чтобы обеспечить типобезопасный интерфейс для существующих функций.
Например, если вы производите список от
CObList
храненияCPerson
объектов, можно добавить функции-оболочкиAddHeadPerson
иGetHeadPerson
, как показано ниже.class CPersonList : public CObList { public: void AddHeadPerson(CPerson* person) { AddHead(person); } const CPerson* GetHeadPerson() { return (CPerson*)GetHead(); } };
Эти функции-оболочки предоставляют безопасный способ добавления и извлечения
CPerson
объектов из производного списка. Вы можете увидеть, что дляGetHeadPerson
функции вы просто инкапсулируете приведение типов.Вы также можете добавить новые функции, определив новые функции, расширяющие возможности коллекции, а не просто упаковав существующие функции в типобезопасные оболочки. Например, статья об удалении всех объектов в коллекции CObject описывает функцию для удаления всех объектов, содержащихся в списке. Эту функцию можно добавить в производный класс как функцию-член.