template                      // or template

bool Stack::push(const Type & item)

{

...

}

If you define a method within the class declaration (an inline definition), you can omit the template preface and the class qualifier.

Listing 14.13 shows the combined class and member function templates. It’s important to realize that these templates are not class and member function definitions. Rather, they are instructions to the C++ compiler about how to generate class and member function definitions. A particular actualization of a template, such as a stack class for handling string objects, is called an instantiation or a specialization. Placing the template member functions in a separate implementation file won’t work. (For a while, the standard did provide the keyword export to allow such a separate implementation file. But not many vendors implemented it. C++11 discontinues that use of export but reserves the export keyword for possible future use.) Because the templates aren’t functions, they can’t be compiled separately. Templates have to be used in conjunction with requests for particular instantiations of templates. The simplest way to make this work is to place all the template information in a header file and to include the header file in the file that will use the templates.

Listing 14.13. stacktp.h

// stacktp.h -- a stack template

#ifndef STACKTP_H_

#define STACKTP_H_

template

class Stack

{

private:

    enum {MAX = 10};    // constant specific to class

    Type items[MAX];    // holds stack items

    int top;            // index for top stack item

public:

    Stack();

    bool isempty();

    bool isfull();

    bool push(const Type & item); // add item to stack

    bool pop(Type & item);        // pop top into item

};

template

Stack::Stack()

{

    top = 0;

}

template

bool Stack::isempty()

{

    return top == 0;

}

template

bool Stack::isfull()

{

    return top == MAX;

}

template

bool Stack::push(const Type & item)

{

    if (top < MAX)

    {

        items[top++] = item;

        return true;

    }

    else

        return false;

}

template

bool Stack::pop(Type & item)

{

    if (top > 0)

    {

        item = items[--top];

        return true;

    }

    else

        return false;

}

#endif

Using a Template Class

Merely including a template in a program doesn’t generate a template class. You have to ask for an instantiation. To do this, you declare an object of the template class type, replacing the generic type name with the particular type you want. For example, here’s how you would create two stacks, one for stacking ints and one for stacking string objects:

Stack kernels;      // create a stack of ints

Stack colonels;  // create a stack of string objects

Seeing these two declarations, the compiler will follow the Stack template to generate two separate class declarations and two separate sets of class methods. The Stack class declaration will replace Type throughout with int, and the Stack class declaration will replace Type throughout with string. Of course, the algorithms you use have to be consistent with the types. The Stack class, for example, assumes that you can assign one item to another. This assumption is true for basic types, structures, and classes (unless you make the assignment operator private) but not for arrays.

Generic type identifiers such as Type in the example are called type parameters, meaning that they act something like variables, but instead of assigning a numeric value to a type parameter, you assign a type to it. So in the kernel declaration, the type parameter Type has the value int.

Notice that you have to provide the desired type explicitly. This is different from ordinary function templates, for which the compiler can use the argument types to a function to figure out what kind of function to generate:

template

void simple(T t) { cout << t << '\n';}

...

simple(2);       // generate void simple(int)

simple("two");   // generate void simple(const char *)

Listing 14.14 modifies the original stack-testing program (Listing 10.12) to use string purchase order IDs instead of unsigned long values.

Listing 14.14. stacktem.cpp

// stacktem.cpp -- testing the template stack class

#include

#include

#include

#include "stacktp.h"

using std::cin;

using std::cout;

int main()

{

    Stack st;   // create an empty stack

    char ch;

    std::string po;

    cout << "Please enter A to add a purchase order,\n"

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги