クラステンプレートインスタンス(友元メンバー関数テンプレートを含む)

5124 ワード

まず、C++のストリーム入出力はCの標準入出力よりもある程度簡潔であると感じますが、簡単ではありません.私が簡単ではないのは、C++がこのストリーム特性を使用するため、あまり異なるプログラミングパターンが生まれたからです.例えば、友元パターンでは、ストリームクラスの演算子の再ロードは友元しかなく、またストリームクラスはコピーできません.
テンプレートにこの演算子を再ロードするときのパターンはさらに奇妙で、どうせ私は理解していないので、しばらくここまで説明します.結局、C++全体の印象には影響しません!
Queue.h
#pragma once
#include 
#include 
using std::ostream;
using std::istream;

template
class QueueItem
{
public:
    QueueItem();
    ~QueueItem();

    void setContext(const T & data);
    T & getContext();

    void setNext(QueueItem * ptr);
    QueueItem * getNext();

private:
    QueueItem(const QueueItem &);
    QueueItem & operator= (const QueueItem &);

private:
    T * context;
    QueueItem * next;
};

template 
class Queue
{
public:
    Queue();
    Queue(const Queue &);
    Queue & operator= (const Queue &);
    ~Queue();

    T & front();
    T & back();

    void pop();
    void push(const T &);

    int isEmpty();

    friend ostream & operator<<  (ostream & os, const Queue & q);
    friend istream & operator>>  (istream & os, Queue & q);

private:
    void destory();
    void copyItems(const Queue & other);

private:
    QueueItem * head;
    QueueItem * tail;
};

template
Queue::Queue()
{
    head = nullptr;
    tail = nullptr;
}

template
inline Queue::Queue(const Queue & other)
{
    head = nullptr;
    tail = nullptr;

    copyItems(other);
}

template
inline Queue & Queue::operator=(const Queue & other)
{
    // TODO: insert return statement here
    destory();

    copyItems(other);
}

template
inline Queue::~Queue()
{
    destory();
}

template
inline T & Queue::front()
{
    // TODO: insert return statement here
    assert(!isEmpty());
    return head->getContext();
}

template
inline T & Queue::back()
{
    // TODO: insert return statement here
    assert(!isEmpty());
    return tail->getContext();
}

template
inline void Queue::pop()
{
    if (isEmpty()) return;

    auto pTmp = head;
    head = head->getNext();
    if (isEmpty()) tail = nullptr;

    delete pTmp;
    pTmp = nullptr;
}

template
inline void Queue::push(const T & data)
{
    auto pElem = new QueueItem;
    pElem->setContext(data);
    pElem->setNext(nullptr);

    if (isEmpty()) {
        head = tail = pElem;
    }
    else {
        tail->setNext(pElem);
        tail = pElem;
    }
}

template
inline void Queue::destory()
{
    while (!isEmpty()) {
        pop();
    }
}

template
inline int Queue::isEmpty()
{
    return head == nullptr;
}

template
inline void Queue::copyItems(const Queue & other)
{
    for (auto p = other->head; p != nullptr; p = p->getNext())
        push(p->getContext());
}

template
inline QueueItem::QueueItem()
{
    context = new T;
    next = nullptr;
}

template
inline QueueItem::~QueueItem()
{
    next = nullptr;
    delete context;
}

template
inline void QueueItem::setContext(const T & data)
{
    *context = data;
}

template
inline T & QueueItem::getContext()
{
    return *context;
}

template
inline void QueueItem::setNext(QueueItem* ptr)
{
    next = ptr;
}

template
inline QueueItem* QueueItem::getNext()
{
    return next;
}

template
ostream & operator<< (ostream & os, const Queue & q)
{
    for (auto p = q.head; p!=nullptr; p=p->getNext())
        os << p->getContext() << " ";
    return os;
}

template
istream & operator>> (istream & os, Queue & q)
{
    T tmp;
    while (os >> tmp, !os.eof())
        q.push(tmp);
    return os;
}


Source.cpp
#include 
#include 
#include "Queue.h"
using namespace std;

void test1()
{
    Queue qIntData;

    qIntData.push(1);
    qIntData.push(2);
    qIntData.push(3);
    qIntData.push(0);

    cout << qIntData << endl;

    qIntData.pop();
    cout << qIntData << endl;

    qIntData.push(4);
    cout << qIntData << endl;
}

void test2()
{
    Queue qIntData;

    cin >> qIntData;

    cout << qIntData << endl;
}


int main(int argc, char ** argv) 
{
    test1();
    test2();

    return 0;
}