C++ Primer 学习笔记_82_模板与泛型编程 --类模板成员[续2]

模板与泛型编程

--类模板成员[续2]

六、完整的Queue

Queue的完整定义:

template <typename Type> class Queue;

template <typename Type>
ostream &operator<<(ostream &,const Queue<Type> &);

template <typename Type> class QueueItem
{
    friend class Queue<Type>;
    friend ostream &
    operator<< <Type>(ostream &,const Queue<Type> &);

    QueueItem(const Type &t):item(t),next(0) {}
    Type item;
    QueueItem *next;
};

template <typename Type> class Queue
{
    friend ostream &
    operator<< <Type>(ostream &,const Queue<Type> &);
public:
    Queue():head(0),tail(0) {}

    template <typename Iter>
    Queue(Iter beg,Iter end):head(0),tail(0)
    {
        copy_elems(beg,end);
    }
    Queue(const Queue &Q):head(0),tail(0)
    {
        copy_elems(Q);
    }

    Queue &operator=(const Queue &);
    ~Queue()
    {
        destroy();
    }

    template <typename Iter>
    void assign(Iter,Iter);

    Type &front()
    {
        return head -> item;
    }
    const Type &front() const
    {
        return head -> item;
    }

    void push(const Type &);
    void pop();
    bool empty() const
    {
        return head == 0;
    }

private:
    QueueItem<Type> *head;
    QueueItem<Type> *tail;

    void destroy();
    void copy_elems(const Queue &);
    template <typename Iter>
    void copy_elems(Iter,Iter);
};

#include “Queue.cpp”
//P559 习题16.43 + P551习题16.34
template <typename Type> class List;
template <typename Type> class ListItem
{
    friend class List<Type>;

    ListItem(Type &t):item(t),next(0) {}
    Type item;
    ListItem *next;
};

template <typename Type> class List
{
public:
    List():front(0),end(0) {}
    List(const List &rhs):front(0),end(0)
    {
        copy_elems(rhs);
    }
    template <class Iter>
    List(Iter first,Iter last):front(first),end(last)
    {
        copy_elems(first,last);
    }
    List &operator=(const List &rhs);
    ~List()
    {
        destroy();
    }

    void insert(ListItem<Type> *ptr,Type &value);
    void del(ListItem<Type> *ptr);
    ListItem<Type> *find(const Type &value);

    ListItem<Type> *first() const
    {
        return front;
    }
    ListItem<Type> *last() const
    {
        return end;
    }

    bool empty() const
    {
        return front == 0;
    }

    Type &getElem(ListItem<Type> *ptr)
    {
        return ptr -> item;
    }

    template <class Iter>
    void assign(Iter,Iter);

private:
    ListItem<Type> *front,*end;

    void destroy();
    void copy_elems(List &);
    template <class Iter>
    void copy_elems(Iter,Iter);
};

template <typename Type>
void List<Type>::destroy()
{
    while (!empty())
        del(front);
}

template <typename Type>
void List<Type>::del(ListItem<Type> *ptr)
{
    ListItem<Type> *p = front;

    while (p != 0 && p != ptr && p -> next != ptr)
    {
        p = p -> next;
    }

    if (p != 0)
    {
        if (p == ptr)
        {
            front = ptr -> next;
        }
        else
        {
            p -> next = ptr -> next;
        }
        if (ptr == end)
        {
            end = ptr -> next;
        }
        delete ptr;
    }
    else
    {
        throw out_of_range("no such element");
    }
}

template <typename Type>
void List<Type>::insert(ListItem<Type> *ptr,Type &val)
{
    ListItem<Type> *pt = new ListItem<Type>(val);

    if (empty())
    {
        front = pt;
    }
    else
    {
        pt -> next = ptr -> next;
        ptr -> next = pt;
    }

    if (ptr == end)
    {
        end = pt;
    }
}

template <typename Type>
void List<Type>::copy_elems(List<Type> &rhs)
{
    for (ListItem<Type> *pt = rhs.front; pt ; pt = pt -> next)
    {
        insert(end,pt -> item);
    }
}

template <class Type> template <typename Iter>
void List<Type>::copy_elems(Iter first,Iter last)
{
    while (first != last)
    {
        insert(end,first -> item);
        first = first -> next;
    }
    insert(end,first -> item);
}

template <typename Type>
List<Type> &List<Type>::operator=(const List<Type> &rhs)
{
    destroy();
    copy_elems(rhs);
}

template <typename Type>
ListItem<Type> *List<Type>::find(const Type &value)
{
    ListItem<Type> *pt = front;

    while (pt && pt -> item != value)
    {
        pt = pt -> next;
    }

    return pt;
}

template <class Type> template <typename Iter>
void List<Type>::assign(Iter first,Iter last)
{
    destroy();
    copy_elems(first,last);
}

//习题16.44
template <class Type> class Queue;
template <typename Type>
ostream &operator<<(ostream &os,const Queue<Type> &);

template <class Type> class Queue
{
    friend ostream &operator<< <Type>(ostream &os,const Queue<Type> &);
public:
    Queue() {}
    template <typename Iter>
    Queue(Iter beg,Iter end):items(beg,end) {}

    template <typename Iter>
    void assign(Iter beg,Iter end)
    {
        items.assign(beg,end);
    }

    Type &front()
    {
        return items.front();
    }
    const Type &front() const
    {
        return items.front();
    }

    void push(const Type &t)
    {
        items.push_back(t);
    }

    void pop()
    {
        items.erase(items.begin());
    }

    bool empty() const
    {
        return items.empty();
    }

private:
    list<Type> items;
};

七、类模板的static成员

类模板可以像任意其他类一样声明static成员。

template <class T> class Foo
{
public:
    static std::size_t count()
    {
        return ctr;
    }

private:
    static std::size_t ctr;
};

定义了名为Foo的类模板,它有一个名为count的publicstatic成员函数和一个名为ctr的privatestatic 数据成员。

Foo类的每个实例化[谨记:不是每个对象]都有自己的static成员:

    Foo<int> fi,fi2,fi3;

    Foo<string> fs;

每个实例化表示截然不同的类型,所以给定实例化所有对象都共享一个static成员。因此,Foo<int>类型的任意对象共享同一static成员 ctr,Foo<string> 类型的对象共享另一个不同的ctr成员。

1、使用类模板的static成员

通常,可以通过类类型的对象访问static成员或者使用作用域操作符直接访问static成员。当然,当试图通过类使用static成员的时候,必须引用实际的实例化:

    Foo<int> fi,fi2;
    size_t ct = Foo<int>::count();
    ct = fi.count();
    ct = fi2.count();
    ct = Foo::count();  //Error:不知道运用哪个实例化

注:static成员函数只有在程序中使用时才进行实例化

2、定义static成员

像使用任意其他static数据成员一样,必须在类外部出现数据成员的定义。在类模板含有static成员的情况下,成员定义必须指出它是类模板的成员:

template <typename Type>
std::size_t Foo<Type>::ctr = 0;

static数据成员的名字以Foo<T>::为前缀,表示成员属于类模板Foo。

C++ Primer 学习笔记_82_模板与泛型编程 --类模板成员[续2],布布扣,bubuko.com

时间: 2024-10-04 18:57:35

C++ Primer 学习笔记_82_模板与泛型编程 --类模板成员[续2]的相关文章

C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]

面向对象编程 --句柄类与继承[续] 三.句柄的使用 使用Sales_item对象能够更easy地编写书店应用程序.代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对象进行的调用的虚行为. 1.比較两个Sales_item对象 在编写函数计算销售总数之前,须要定义比較Sales_item对象的方法.要用Sales_item作为关联容器的keyword,必须能够比較它们.关联容器默认使用keyword类型的小于操作符,可是假设给Sales_item定义小于操作符,

C++ Primer 学习笔记_82_模板与泛型编程 -类模板成员[续二]

模板与泛型编程 --类模板成员[续2] 六.完整的Queue类 Queue的完整定义: template <typename Type> class Queue; template <typename Type> ostream &operator<<(ostream &,const Queue<Type> &); template <typename Type> class QueueItem { friend clas

C++ Primer 学习笔记_81_模板与泛型编程 --类模板成员[续1]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height

C++ Primer 学习笔记_80_模板与泛型编程 --类模板成员

模板与泛型编程 --类模板成员 引言: 这一节我们介绍怎样实现前面提到的Queue模板类. 标准库将queue实现为其他容器之上的适配器.为了强调在使用低级数据结构中设计的编程要点,我们将Queue实现为链表.实际上,在我们的实现中使用标准库可能是个更好的决定!!-_-. 1.Queue的实现策略 如图所示,我们实现两个类: 1)QueueItem类表示Queue的链表中的节点,该类有两个数据成员item和next: a. item保存Queue中元素的值,它的类型随Queue的每个实例而变化:

C++ Primer 学习笔记_81_模板与泛型编程 -类模板成员[续一]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height

C++ Primer 学习笔记_89_用于大型程序的工具 --异常处理[续2]

用于大型程序的工具 --异常处理[续2] 八.自动资源释放 考虑下面函数: void f() { vector<string> v; string s; while (cin >> s) { v.push_back(s); } string *p = new string[v.size()]; //... delete p; } 在正常情况下,数组和vector都在退出函数之前被撤销,函数中最后一个语句释放数组,在函数结束时自动撤销vector. 但是,如果在函数内部发生异常,则将

C++ Primer 学习笔记_94_用于大型程序的工具 --命名空间[续3]

用于大型程序的工具 --命名空间[续3] 六.重载与命名空间 正如我们所见,每个命名空间维持自己的作用域,因此,作为两个不同命名空间的成员的函数不能互相重载.但是,给定命名空间可以包含一组重载函数成员. 1.候选函数与命名空间 命名空间对函数匹配有两个影响.一个影响是明显的:using声明或using 指示可以将函数加到候选集合.另一个影响则微妙得多. 正如前节所见,有一个或多个类类型形参的函数的名字查找包括定义每个形参类型的命名空间.这个规则还影响怎样确定候选集合,为找候选函数而查找定义形参类

C++ Primer 学习笔记_100_特殊工具与技术 --优化内存分配[续2]

特殊工具与技术 --优化内存分配[续2] 七.一个内存分配器基类 预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造:释放元素的时候,将它们放回预先分配对象的块中,而不是将内存实际返还给系统.这种策略常被称为维持一个自由列表.可以将自由列表实现为已分配但未构造的对象的链表. 我们将定义一个名为 CachedObj 的新类来处理自由列表.像 QueueItem 这样希望优化其对象分配的类可以使用 CachedObj 类,而不用直接实现自己的 new 和 del

C++ Primer 学习笔记_99_特殊工具与技术 --优化内存分配[续1]

特殊工具与技术 --优化内存分配[续1] 三.operator new函数和operator delete 函数 – 分配但不初始化内存 首先,需要对new和delete表达式怎样工作有更多的理解.当使用new表达式 string *sp = new string("initialized"); 的时候,实际上发生三个步骤: 1)首先,表达式调用名为operator new 的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象; 2)接下来,运行该类型的一个构造函数