250 likes | 272 Views
Learn how to work with containers in C++ using both STL and Qt libraries. Explore the operations and best practices for vectors, lists, hashes, and more. Dive into iterator usage and advanced container manipulation techniques.
E N D
Containers Jason Goffeney 2/23/2006
Containers • The STL is a standard part of probably all C++ implementations • It features implementations of most of the handy basic container classes, such as, linked lists, vectors, and hashes. • Qt also implements many of these containers as well as many more. • STL classes will work with any C++ code while Qt classes will only work with Qt/C++ code.
Containers • How to include in your program. • STL classes use C++ style includes (which means you leave the .h off its header file). • #include <vector> • #include <list> • Qt 4.0 classes also use C++ style include but also have capitalization • #include <QVector> • #include <QList>
Containers • How to include in your program. • Note: STL classes are in the std namespace which means that you usually need to prepend std:: to each STL keyword when using it • std::vector<int> newVector • If you want to avoid doing this then follow your STL includes with using namespace std; #include <vector> #include <list> Using namespace std;
Containers • Both STL and Qt containers are designed as templates which take a class or struct as a parameter for their declaration. • For example, suppose you have a class called Point and want to make a list of points • STL: list<Point> pointList; • Qt: QList<Point> pointList;
Containers • This will also work for primitive types such as int, float, char, etc. • STL: list<int> pointList; • Qt: QList<float> floatList; • If you want to create them as pointers than you can do that too. • STL: list<int> * pointList = new list<int>(); • Qt: QList<float> * floatList = new QList<float>();
Containers: Style Notes • If a container will need to exist outside of the scope of a single function then it is generally declared in the class definition in the header file (usually in the private section). • For a non-pointer container then you are done and can just use it in the rest of your code. • For a pointer declare it in the header and create the container in the constructor of the source file. • In Header: QVector<Point> * ptList; • In Constructor: ptList = new QVector<Point>();
Containers: Style Notes • For the remainder of this I will likely assume non-pointers and use a “.” to show access to methods of the containers. • But pointers are useful and speed up passing containers into functions. The take home point though is that “->” is used to access methods from pointers.
Containers: Vector • Vectors are simple dynamically expandable and collapsible lists. • Operations: • Construct: • STL: vector<float> myVector; • Qt: QVector<float> myVector; • Add an element to the end • STL: myVector.push_back(5.34); • Qt: myVector.append(5.34);
Containers: Vector • Operations: • Insert (position, item): • STL, Qt: myVector.insert(2, 4.35); • Remove an element (position): • STL: myVector.erase(5); • Qt: myVector.remove(5); • Access an element (position): • STL/Qt: float f1 = myVector.at(3); • myVector.at(0) = 3.67;
Containers: Vector • Operations: • Get current size of vector • STL, Qt: int size = myVector.size(); • Get first element • STL, Qt: float first = myVector.front(); • Get last element • STL, Qt: float first = myVector.back();
Containers: Vector • Operations: • Iterating through a vector • There are two ways to iterate through vectors • The old way: for(i = 0; i < myVector.size(); i++) { printf( “The float is %f\n”, myVector.at(i)); } • Problem: If you remove elements from the list while iterating bad things may happen
Containers: Vector • STL Iterators: vector<int> myIntVector; vector<int>::iterator myIntVectorIterator; //Iterator object for list // Add some elements to myIntVector myIntVector.push_back(1); myIntVector.push_back(4); myIntVector.push_back(8); for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) { cout<<*myIntVectorIterator<<" "; //Should output 1 4 8 }
Containers: Vector • Qt Iterators: QVector<float> vector; ... QVectorIterator<float> i(vector); while (i.hasNext()) { cout << i.next(); }
Containers: Vector • These are a few of the ways it is possible to manipulate STL and Qt Vector containers. • Look at their references to learn more.
Other Containers: • Lists – Doubly linked list that support faster insertions and deletions than vector. • Hashes – A container that stores and retrieves an item by a key. Allows for very fast lookups of items but only a single item can be stored per key • Multihash – Like a hash except multiple objects can be stored per key with • Stacks, Queues, etc…
Example • One of the basic model formats is the Alias .obj format. It defines a list of vertex coordinates and then a list of faces and the indices of the vertices that compose them. 2. (0,50) 3. (50,50) Vertices v 0 0 v 50 0 v 0 50 v 50 50 Face f 0 1 2 f 1 3 2 1. (50,0) 0. (0,0)
Example • I want a way to store my simple model use later. So I need to make some classes or structures. • s are simple to represent as a couple of Integers. (Note: the QPoint class already exists in Qt). struct Point2i { //A point that holds 2 integer values int x, y; };
Example • I want a way to store my simple model use later. So I need to make some classes or structures. • Vertices are simple to represent as a couple of Integers. (Note: the QPoint class already exists in Qt). class Vertex2i { public: //Constructor Vertex2i(int xi, int yi)(x = xi; y = yi;} //A point that holds 2 integer values int x, y; };
Example • A face can be composed of any number of vertices so a list of point indices could be useful here. class Face { public: //A face holds ? vertices vector<int> vertices; };
Example • I will load my vertices into a vector of vertices. vector<Vertex2i> vertexList; Vertex2i v0(0,0); Vertex2i v1(50,0); Vertex2i v2(0,50); Vertex2i v3(50,50); vertexList.push_back(v0); vertexList.push_back(v1); vertexList.push_back(v2); vertexList.push_back(v3);
Example • I will build my Faces and load them into a list as well. vector<Face> faceList; Face f1; f1.vertices.push_back(0); f1.vertices.push_back(1); f1.vertices.push_back(2); Face f2; f2.vertices.push_back(1); f2.vertices.push_back(3); f2.vertices.push_back(2); faceList.push_back(f1); faceList.push_back(f2);
Example • Now I want to draw the faces. for(int j = 0; j < faceList.size(); j++) { glBegin(GL_LINE_LOOP); //Start drawing vector<int> tempList = faceList.at(j).vertices; for(int m = 0; m < tempList.size(); m++) { int vIdx = tempList.at(m); glVertex2i( vertexList.at(vIdx).x, vertexList.at(vIdx).y); } glEnd(); //Stop drawing }
Example • If you want to try it: • Put the Vertex2i and Face class definitions in the top of your GLWidget.h below the includes. • Declare the vectors in your GLWidget class with the appropriate includes. • In the GLWidget constructor put all the loading code • In the GLWidget paintGL method put the drawing code right below the glClear statement
Example • Generally, a model will be loaded from a file which makes the vector filling less tedious. • Notice that by adding a z coordinate to he Vertex class this will easily handle 3D models as well.