打印

C++类模板

[复制链接]
615|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2015-11-27 08:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*
* This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
* copyright and warranty notices given in that book:
*
* "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
*
*
* "The authors and publisher have taken care in the preparation of this book,
* but make no expressed or implied warranty of any kind and assume no
* responsibility for errors or omissions. No liability is assumed for
* incidental or consequential damages in connection with or arising out of the
* use of the information or programs contained herein."
*
* Permission is granted for this code to be used for educational purposes in
* association with the book, given proper citation if and when posted or
* reproduced.Any commercial use of this code requires the explicit written
* permission of the publisher, Addison-Wesley Professional, a division of
* Pearson Education, Inc. Send your request for permission, stating clearly
* what code you would like to use, and in what specific way, to the following
* address:
*
*         Pearson Education, Inc.
*         Rights and Permissions Department
*         One Lake Street
*         Upper Saddle River, NJ  07458
*         Fax: (201) 236-3290
*/

#ifndef BLOB_H
#define BLOB_H

#include <iterator>
#include <string>
#include <vector>
#include <cstddef>
#include <stdexcept>
#include <utility>
#include <tr1/memory>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <stdexcept>

// forward declarations needed for friend declarations in Blob
template <typename> class BlobPtr;   
template <typename> class Blob; // needed for parameters in operator==
template <typename T>
    bool operator==(const Blob<T>&, const Blob<T>&);

template <typename T> class Blob {
        // each instantiation of Blob grants access to the version of
        // BlobPtr and the equality operator instantiated with the same type
        friend class BlobPtr<T>;
        friend bool operator==<T>
               (const Blob<T>&, const Blob<T>&);
public:
        typedef T value_type;
        typedef typename std::vector<T>::size_type size_type;

        // constructors
        Blob();
        template <typename It> Blob(It b, It e);
        Blob(T*, std::size_t);

        // return BlobPtr to the first and one past the last elements
        BlobPtr<T> begin() { return BlobPtr<T>(*this); }
        BlobPtr<T> end()
            { BlobPtr<T> ret = BlobPtr<T>(*this, data->size());
              return ret; }

        // number of elements in the Blob
        size_type size() const { return data->size(); }
        bool empty() const { return data->empty(); }

        // add and remove elements
        void push_back(const T &t) {data->push_back(t);}
        void pop_back();

        // element access
        T& front();
        T& back();
        T& at(size_type);
        const T& back() const;
        const T& front() const;
        const T& at(size_type) const;
        T& operator[](size_type i);
        const T& operator[](size_type i) const;

        void swap(Blob &b) { data.swap(b.data); }
private:
        std::tr1::shared_ptr<std::vector<T> > data;

        // throws msg if data[i] isn't valid
        void check(size_type i, const std::string &msg) const;
};

// constructors
template <typename T>
Blob<T>::Blob(T *p, std::size_t n):
              data(new std::vector<T>(p, p + n)) { }

template <typename T>
Blob<T>::Blob():
                  data(new std::vector<T>()) { }

template <typename T>     // type parameter for the class
template <typename It>    // type parameter for the constructor
    Blob<T>::Blob(It b, It e):
              data(new std::vector<T>(b, e)) { }

// check member
template <typename T>
void Blob<T>::check(size_type i, const std::string &msg) const
{
        if (i >= data->size())
                throw std::out_of_range(msg);
}

// element access members
template <typename T>
T& Blob<T>::front()
{
        // if the vector is empty, check will throw
        check(0, "front on empty Blob");
        return data->front();
}

template <typename T>
T& Blob<T>::back()
{
        check(0, "back on empty Blob");
        return data->back();
}

template <typename T> void Blob<T>::pop_back()
{
        check(0, "pop_back on empty Blob");
        data->pop_back();
}

template <typename T>
const T& Blob<T>::front() const
{
        check(0, "front on empty Blob");
        return data->front();
}

template <typename T>
const T& Blob<T>::back() const
{
        check(0, "back on empty Blob");
        return data->back();
}

template <typename T>
T& Blob<T>::at(size_type i)
{
        // if i is too big, check will throw, preventing access to a nonexistent element
        check(i, "subscript out of range");
        return (*data)[i];  // (*data) is the vector to which this object points
}

template <typename T>
const T&
Blob<T>::at(size_type i) const
{
        check(i, "subscript out of range");
        return (*data)[i];
}

template <typename T>
T& Blob<T>::operator[](size_type i)
{
        // if i is too big, check will throw, preventing access to a nonexistent element
        check(i, "subscript out of range");
        return (*data)[i];
}

template <typename T>
const T&
Blob<T>::operator[](size_type i) const
{
        check(i, "subscript out of range");
        return (*data)[i];
}

// operators
template <typename T>
std::ostream&
operator<<(std::ostream &os, const Blob<T> a)
{
        os << "< ";
        for (size_t i = 0; i < a.size(); ++i)
                os << a[i] << " ";
        os << " >";
        return os;
}

template <typename T>
bool
operator==(const Blob<T> lhs, const Blob<T> rhs)
{
        if (rhs.size() != lhs.size())
                return false;
        for (size_t i = 0; i < lhs.size(); ++i) {
                if (lhs[i] != rhs[i])
                        return false;
        }
        return true;
}

// BlobPtr throws an exception on attempts to access a nonexistent element
template <typename T>
bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);

template <typename T> class BlobPtr : public std::iterator<std::bidirectional_iterator_tag,T> {
        friend bool
        operator==<T>(const BlobPtr<T>&, const BlobPtr<T>&);
public:
    BlobPtr(): curr(0) { }
    BlobPtr(Blob<T> &a, size_t sz = 0):
                wptr(a.data), curr(sz) { }

        T &operator[](std::size_t i)
        { std::tr1::shared_ptr<std::vector<T> > p =
                                        check(i, "subscript out of range");
          return (*p)[i];  // (*p) is the vector to which this object points
        }

        const T &operator[](std::size_t i) const
        { std::tr1::shared_ptr<std::vector<T> > p =
                                        check(i, "subscript out of range");
          return (*p)[i];  // (*p) is the vector to which this object points
        }
   
    T& operator*() const
        { std::tr1::shared_ptr<std::vector<T> > p =
                                        check(curr, "dereference past end");
          return (*p)[curr];  // (*p) is the vector to which this object points
        }
    T* operator->() const
        { // delegate the real work to the dereference operator
         return & this->operator*();
        }

    // increment and decrement
    BlobPtr& operator++();       // prefix operators
    BlobPtr& operator--();

    BlobPtr operator++(int);     // postfix operators
    BlobPtr operator--(int);
   
private:
        // check returns a shared_ptr to the vector if the check succeeds
        std::tr1::shared_ptr<std::vector<T> >
                check(std::size_t, const std::string&) const;

        // store a weak_ptr, which means the underlying vector might be destroyed
    std::tr1::weak_ptr<std::vector<T> > wptr;  
    std::size_t curr;      // current position within the array
};

// equality operators
template <typename T>
bool operator==(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
        return lhs.wptr.lock().get() == rhs.wptr.lock().get() &&
               lhs.curr == rhs.curr;
}

template <typename T>
bool operator!=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
        return !(lhs == rhs);
}

// check member
template <typename T>
std::tr1::shared_ptr<std::vector<T> >
BlobPtr<T>::check(std::size_t i, const std::string &msg) const
{
        std::tr1::shared_ptr<std::vector<T> > ret =
                                        wptr.lock();   // is the vector still around?
        if (!ret)
                throw std::runtime_error("unbound BlobPtr");
        if (i >= ret->size())
                throw std::out_of_range(msg);
        return ret; // otherwise, return a shared_ptr to the vector
}

// member operators
// postfix: increment/decrement the object but return the unchanged value
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
    // no check needed here; the call to prefix increment will do the check
    BlobPtr ret = *this;   // save the current value
    ++*this;     // advance one element; prefix ++ checks the increment
    return ret;  // return the saved state
}

template <typename T>
BlobPtr<T> BlobPtr<T>::operator--(int)
{
    // no check needed here; the call to prefix decrement will do the check
    BlobPtr ret = *this;  // save the current value
        --*this;     // move backward one element; prefix -- checks the decrement
    return ret;  // return the saved state
}

// prefix: return a reference to the incremented/decremented object
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator++()
{
        // if curr already points past the end of the container, can't increment it
        check(curr, "increment past end of BlobPtr");
    ++curr;       // advance the current state
    return *this;
}

template <typename T>
BlobPtr<T>& BlobPtr<T>::operator--()
{
        // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element
    check(-1, "decrement past begin of BlobPtr");
    return *this;
}
#endif

相关帖子

沙发
keer_zu|  楼主 | 2015-11-27 08:42 | 只看该作者
这是C++ Primer上的例子,有个运算符重载"operator=="是在类模板外面的,它是类模板Blob的友元,相当于友元函数吧

使用特权

评论回复
板凳
keer_zu|  楼主 | 2015-11-27 09:00 | 只看该作者
为什么要把重载运算符 opertor== 放在类外部呢?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1352

主题

12436

帖子

53

粉丝