Container classes are used to contain stuff .

A container class is simply something that holds values - like an array, but with extra functionality. They usually store 'nodes', with each node containing the wanted value plus some more info, such as how to get to the next node. The nodes are dynamically allocated as necessary, so a container class isn't a fixed size.

For example, you get a linked list - this stores a node for each element, plus a pointer to get to the next node (so that you can have an unlimited amount of nodes - but you have to hop from one to the next using pointers, since it won't be a continuous area of memory like an array). You might also have a doubly-linked list, which would store two pointers - one for the previous node and one for the next. This would let you move both ways but with extra overhead (one more pointer, 4 bytes more per node).

You could also have a binary tree. These have nodes with the value plus two pointers - a left and a right one. New nodes are allocated on demand, again. You add to the left of the node if the value is less than the examined node, otherwise add it to the right. Recursion is handy here. You might have to rearrange things when you delete nodes, though, and it can be a pain keeping them balanced.

There are queues too - these map to the real-life concept. If you add something, it starts at the end of the queue. You remove from the start of the queue (imagine a line in a shop, for example). This is first in, first out.

In short, containers are fancy ways to store data. Each has a different set of properties (such as fast/slow insertion, fast/slow deletion, fast/slow search, high/low memory use, and so on). You pick a suitable container class and away you go!

There's also the concept of iterators: you get an iterator to a container class, then keep moving it on until the last element. This means that you don't care about the underlying structure of the object, and it also lets you specify ranges.

The problem is that the classes in the VCL are a bit lame, really. They do the job but with pointers, which is type-unsafe (you could coerce the compiler into, say, treating a pointer from one class as a pointer to another). If you used templates, you could outline the basic storage format ("store strings, store ints", whatever) and the compiler would generate classes for you. This would result in more type safety, but code bloat too (since each templated class w/ a type is totally separate).

Example, using hypothetical generic stuff in Delphi, a linked list node before-and-after might look like this:

[pascal]type
PNode = ^TNode;
TNode = record
Data: Integer;
Next: PNode;
end;

//versus...

PNode = ^TNode;

template(MyType)
TNode = record
Data: MyType;
Next: PNode;
end;
end;[/pascal]
The first would be hard-coded to store only integers - the second could be passed in a type ("MyList: TNode<integer>" or "MyList: TNode<string>") and the compiler would generate the appropriate thing. This means you have a general-purpose prototype that can store any given value, with the compiler ensuring that it does the right thing.