[ fromfile: templates.xml id: classtemplates ]
Like functions, classes can also use parameterized types. A class template specifies how to produce generic data structures of a particular type. All Qt container classes and, of course, all containers in the Standard Template Library (STL) are parameterized. The parameter is the answer to the question, "Container of what?" Figure 11.1 shows a UML diagram of two template classes.
UML locates the template parameter in a small offset box in the upper-right corner of the class box. Example 11.3 contains definitions for these classes.
Example 11.3. src/containers/stack/stack.h
[ . . . . ] #include <QDebug> template<class T> class Node { public: Node(T invalue): m_Value(invalue), m_Next(0) {} ~Node() ; T getValue() const {return m_Value;} void setValue(T value) {m_Value = value;} Node<T>* getNext() const {return m_Next;} void setNext(Node<T>* next) {m_Next = next;} private: T m_Value; Node<T>* m_Next; }; template<class T> Node<T>::~Node() { qDebug() << m_Value << " deleted " << endl; if(m_Next) { delete m_Next; } } template<class T> class Stack { public: Stack(): m_Head(0), m_Count(0) {} ~Stack<T>() {delete m_Head;} ; void push(const T& t); T pop(); T top() const; int count() const; private: Node<T>* m_Head; int m_Count; };
<include src="src/containers/stack/stack.h" mode="cpp" href="src/containers/stack/stack.h" id="stackh" segid="classdef"/>
All template definitions (classes and functions) must appear in the header file. This is necessary for the compiler to generate code from a template declaration.
Notice in both Example 11.3 and Example 11.4, the required template declaration code:
template<class T>
precedes each class or function definition that has a template parameter in its name.
Example 11.4. src/containers/stack/stack.h
[ . . . . ] template <class T> void Stack<T>::push(const T& value) { Node<T>* newNode = new Node<T>(value); newNode->setNext(m_Head); m_Head = newNode; ++m_Count; } template <class T> T Stack<T>::pop() { Node<T>* popped = m_Head; if (m_Head != 0) { m_Head = m_Head->getNext(); T retval = popped->getValue(); popped->setNext(0); delete popped; --m_Count; return retval; } return 0; }
<include src="src/containers/stack/stack.h" mode="cpp" href="src/containers/stack/stack.h" id="stackhdef" segid="fundef"/>
The creation of objects is handled generically in the template function, push()
.
The destructor for the Node<T>
class recursively deletes Node
pointers until it reaches one with a zero m_Next
pointer.[83]
Controlling creation and destruction of Node<T>
objects this way enables Stack<T>
to completely manage its dynamic memory.
Example 11.5 contains some client code to demonstrate these classes.
Example 11.5. src/containers/stack/main.cpp
#include <QDebug> #include <QString> #include "stack.h" int main() { Stack<int> intstack1, intstack2; int val; for (val = 0; val < 4; ++val) { intstack1.push(val); intstack2.push(2 * val); } while (intstack1.count()) { val = intstack1.pop(); qDebug() << val; } Stack<QString> stringstack; stringstack.push("First on"); stringstack.push("second on"); stringstack.push("first off"); QString val2; while (stringstack.count()) { val2 = stringstack.pop(); qDebug() << val2; } qDebug() << "Now intstack2 will self destruct."; return 0; }
<include src="src/containers/stack/main.cpp" href="src/containers/stack/main.cpp" id="stackmaincpp" mode="cpp"/>
When you run the program, you should see the following output.
3 deleted 3 2 deleted 2 1 deleted 1 0 deleted 0 first off deleted "first off" second on deleted "second on" First on deleted "First on" Now intstack2 will self destruct. 6 deleted 4 deleted 2 deleted 0 deleted
Q_OBJECT and Template Classes | |
---|---|
Because additional code needs to be generated by moc for each |
[83] This is a consequence of the fact that calling delete
on a pointer automatically invokes the destructor associated with that pointer.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |