Udostępnij przez


Instrukcje: tworzenie kolekcji Type-Safe

W tym artykule wyjaśniono, jak tworzyć bezpieczne kolekcje typów dla własnych typów danych. Tematy obejmują:

Biblioteka klas programu Microsoft Foundation udostępnia wstępnie zdefiniowane kolekcje bezpieczne dla typów na podstawie szablonów języka C++. Ponieważ są to szablony, te klasy pomagają zapewnić bezpieczeństwo typów oraz łatwość użycia bez konieczności rzutowania typu i innych dodatkowych prac związanych z używaniem klasy nieszablonowej w tym celu. Przykładowy zestaw COLLECT MFC demonstruje użycie klas kolekcji opartych na szablonach w aplikacji MFC. Ogólnie rzecz biorąc, należy używać tych klas za każdym razem, gdy piszesz nowy kod kolekcji.

Użycie klas Template-Based w celu zapewnienia bezpieczeństwa typów

Aby użyć klas opartych na szablonach

  1. Zadeklaruj zmienną typu klasy kolekcji. Przykład:

    CList<int, int> m_intList;
    
  2. Wywołaj funkcje składowe obiektu kolekcji. Przykład:

    m_intList.AddTail(100);
    m_intList.RemoveAll();
    
  3. W razie potrzeby zaimplementuj funkcje pomocnika i SerializeElements. Aby uzyskać informacje na temat implementowania tych funkcji, zobacz Implementowanie funkcji pomocnika.

W tym przykładzie pokazano deklarację listy liczb całkowitych. Pierwszy parametr w kroku 1 to typ danych przechowywanych jako elementy listy. Drugi parametr określa, w jaki sposób dane mają być przekazywane i zwracane z funkcji składowych klasy kolekcji, takich jak Add i GetAt.

Implementowanie funkcji pomocnika

Szablonowe klasy kolekcji CArray, CList i CMap używają pięciu globalnych funkcji pomocniczych, które można dostosować do potrzeb klasy kolekcji pochodnej. Aby uzyskać informacje na temat tych funkcji pomocniczych, zobacz Pomocnicy klasy kolekcji w Referencji MFC. Implementacja funkcji serializacji jest niezbędna w przypadku większości zastosowań klas kolekcji opartych na szablonach.

Serializowanie elementów

Klasy CArray, CList i CMap wywołują SerializeElements w celu przechowywania elementów kolekcji lub ich odczytu z archiwum.

Domyślna implementacja funkcji pomocniczej SerializeElements wykonuje operację bitowego zapisu z obiektów do archiwum lub bitowego odczytu z archiwum do obiektów, zależnie od tego, czy obiekty są przechowywane w archiwum, czy pobierane z niego. Zastąpij SerializeElements , jeśli ta akcja nie jest odpowiednia.

Jeśli kolekcja przechowuje obiekty pochodzące z CObject i używasz makra IMPLEMENT_SERIAL w implementacji klasy elementu kolekcji, możesz skorzystać z funkcji serializacji wbudowanej w CArchive i 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);
   }
}

Przeciążone operatory wstawiania dla CArchive wywołują funkcję CObject::Serialize (lub zastąpienie tej funkcji) dla każdego obiektu CPerson.

Używanie klas kolekcji nietemplatowych

MFC obsługuje również klasy kolekcji wprowadzone w MFC w wersji 1.0. Te klasy nie są oparte na szablonach. Mogą one służyć do przechowywania danych obsługiwanych typów CObject*, , UINTDWORDi CString. Za pomocą tych wstępnie zdefiniowanych kolekcji (takich jak CObList) można przechowywać kolekcje dowolnych obiektów pochodzących z CObject. MFC udostępnia również inne wstępnie zdefiniowane kolekcje do przechowywania typów pierwotnych, takich jak UINT i wskaźniki void (void*). Ogólnie rzecz biorąc, często przydatne jest zdefiniowanie własnych kolekcji bezpiecznych pod kątem typów do przechowywania obiektów bardziej konkretnej klasy i jej pochodnych. Należy pamiętać, że używanie klas kolekcji, które nie są oparte na szablonach, wymaga więcej pracy niż korzystanie z klas opartych na szablonach.

Istnieją dwa sposoby tworzenia kolekcji bezpiecznych typowo za pomocą kolekcji nietemplatowych.

  1. W razie potrzeby użyj kolekcji nietemplatowych z konwersją typów. Jest to łatwiejsze podejście.

  2. Wywieść z i rozszerzyć kolekcję typów bez wzorca, bezpieczną pod względem typów.

Aby użyć kolekcji nieszablonowych z rzutowaniem typów

  1. Użyj jednej z nieplaterowych klas, takich jak CWordArray, bezpośrednio.

    Możesz na przykład utworzyć CWordArray i dodać do niego dowolne wartości 32-bitowe, a następnie je pobrać. Nie ma nic więcej do zrobienia. Wystarczy użyć wstępnie zdefiniowanych funkcji.

    Możesz również użyć wstępnie zdefiniowanej kolekcji, takiej jak CObList, do przechowywania dowolnych obiektów pochodzących z CObject. Kolekcja CObList jest zdefiniowana do przechowywania wskaźników na CObject. Podczas pobierania obiektu z listy może być konieczne rzutowanie wyniku do odpowiedniego typu, ponieważ CObList funkcje zwracają wskaźniki do CObject. Na przykład, jeśli przechowujesz CPerson obiekty w CObList kolekcji, musisz rzutować pobrany element na wskaźnik do CPerson obiektu. W poniższym przykładzie użyto kolekcji CObList, aby przechowywać obiekty CPerson.

    CPerson* p1 = new CPerson();
    CObList myList;
    
    myList.AddHead(p1);   // No cast needed
    CPerson* p2 = (CPerson*)myList.GetHead();
    

    Ta technika wykorzystania wstępnie zdefiniowanego typu kolekcji i rzutowania, gdy jest to konieczne, może być odpowiednia dla wielu potrzeb związanych z kolekcją. Jeśli potrzebujesz dalszych funkcji lub większej liczby typów bezpieczeństwa, użyj klasy opartej na szablonach lub wykonaj następną procedurę.

Aby uzyskać i rozszerzyć bezpieczną dla typów kolekcję niestemplatową

  1. Derywuj własną klasę kolekcji z jednej ze wstępnie zdefiniowanych klas nieszablonowych.

    Podczas tworzenia klasy pochodnej można dodać typowo bezpieczne funkcje opakowujące, aby zapewnić typowo bezpieczny interfejs do istniejących funkcji.

    Jeśli na przykład stworzono listę z CObList do przechowywania CPerson obiektów, możesz dodać funkcje otoki AddHeadPerson i GetHeadPerson, jak pokazano poniżej.

    class CPersonList : public CObList
    {
    public:
       void AddHeadPerson(CPerson* person)
       {
          AddHead(person);
       }
    
       const CPerson* GetHeadPerson()
       {
          return (CPerson*)GetHead();
       }
    };
    

    Funkcje opakowujące zapewniają bezpieczny typowo sposób na dodawanie i pobieranie CPerson obiektów z listy dziedziczonej. Można zauważyć, że dla funkcji GetHeadPerson po prostu dokonujesz rzutowania typów.

    Możesz również dodać nową funkcjonalność, definiując nowe rozszerzenia, które zwiększają możliwości kolekcji, zamiast po prostu opakowywać istniejące funkcje w bezpieczne dla typów opakowania. Na przykład artykuł Usuwanie wszystkich obiektów w kolekcji CObject opisuje funkcję usuwania wszystkich obiektów znajdujących się na liście. Tę funkcję można dodać do klasy pochodnej jako funkcję składową.

Zobacz także

Kolekcje