類模板以及賦值運算符重載、拷貝構造函數

編譯器默認的拷貝構造函數,是發生的淺拷貝,像指針的賦值就會讓指針指向同一個地址空間,析構時就會對同一個地址空間釋放兩次,就會造成程序崩潰.
自定義在模板內的拷貝構造函數:

Queue(const Queue<T> &src)//類對象的拷貝構造函數
    {
        //Queue();
        _pfirst = _prear = NULL;
        QueueItem*p =src._pfirst;
        while (p != NULL)
        {
            addQue(p->_data);
            p = p->_pnext;
        }
    }

上述拷貝構造函數僅僅支持同種類型的對象之間的拷貝構造,對於不同類型的對象之間的拷貝構造就需要建立如下模板(但是必須在定義友元類):

private中需要先定義如下:
template<typename E>
friend class Queue;
template<typename E>
    Queue(const Queue<E>&src)//自定義拷貝構造函數的模板,Queue<E>爲新類型,必須先聲明Queue<E>類類型爲此類型的友元類型,此模板不能替代上述同類型的拷貝構造
    {
        cout << "const Queue<E>& 模板" << endl;
        _pfirst = _prear = NULL;
        Queue<E>::QueueItem*p = src._pfirst;//必須加Queue<E>這個作用域,否則指針的類型不一樣,會出現錯誤。
        while (p != NULL)
        {
            addQue(p->_data);
            p = p->_pnext;
        }
    }

此模板在模板外定義:

//不同類型對象的拷貝構造函數的模板外定義
template<typename T>
template<typename E>
Queue<T>::Queue(const Queue<E> &src)
{
    Queue<E>::QueueItem*p = src._pfirst;
    while (p != NULL)
    {
        addQue(p->_data);
        p = p->_pnext;
    }
}

此支持不同類型對象之間的拷貝構造函數不能替代同種類型對象的的拷貝構造函數。
賦值運算符同樣需要自定義,否則就會出現和拷貝構造相同的問題,自定義的相同類型的對象之間的賦值運算符重載函數:

void operator=(const Queue<T> &src)//自定義的賦值運算符的重載函數,避免了編譯器默認的淺拷貝,造成的內存泄漏等問題
    {
        cout << "operator Queue<T> &src" << endl;
        if (this == &src)
        {
            return;
        }
        if (_pfirst != NULL)
        {
            while (_pfirst != _prear)
            {
                QueueItem*tmp = _pfirst->_pnext;
                delete _pfirst;
                _pfirst = tmp;
            }
        }
        delete _pfirst;
        _pfirst = _prear = NULL;//必須將頭尾指針指向NULL,否則就會從_pfirst的位置向後添加元素,而_pfirst的位置確是已經釋放的隨機值

        QueueItem*p = src._pfirst;
        while (p != NULL)
        {
            addQue(p->_data);
            p = p->_pnext;
        }
    }

不同類型對象之間的賦值運算符的重載函數模板:

template<typename E>
    void operator=(const Queue<E> &src)//不同類型對象之間的賦值運算
    {
        cout << "operator Queue<T> &src模板" << endl;

        if (_pfirst != NULL)
        {
            while (_pfirst != _prear)
            {
                QueueItem*tmp = _pfirst->_pnext;
                delete _pfirst;
                _pfirst = tmp;
            }
        }
        delete _pfirst;
        _pfirst = _prear = NULL;

        Queue<E>::QueueItem*p = src._pfirst;
        while (p != NULL)
        {
            addQue(p->_data);
            p = p->_pnext;
        }
    }

在沒有給定此模板時,此句int_queue = double_queue會先調用不同類型對象直接的拷貝構造函數先生成同種類型得臨時對象,再調用同種類型的賦值運算符的重載函數賦值成功,當定義了此 模板就直接實例化此模板一次就完成賦值。

主函數:


int main()
{

    Queue<int> int_queue;
    int_queue.addQue(10);
    int_queue.addQue(20);

    Queue<double> double_queue = Queue<double>();
    double_queue.addQue(30.5);

    Queue<int> int1_queue(int_queue);//相同類型對象之間的拷貝構造,需要自定義拷貝構造函數,否則編譯器默認的造成淺拷貝(指針的賦值)導致出錯
    int1_queue.addQue(40);

    Queue<int> int2_queue(double_queue);//不同類型對象之間的拷貝構造,編譯器不會產生,需要自定義。
    cout <<"int_queue------------------------------------------" << endl;
    int_queue.show();
    cout << "int1_queue----------------------------------------" << endl;
    int1_queue.show();
    cout << "double_queue--------------------------------------" << endl;
    double_queue.show();
    cout << "int2_queue----------------------------------------" << endl;
    int2_queue.show();
    cout << "賦值運算符的重載函數---------------------------------------------" << endl;
    //int_queue = int1_queue;
    //int_queue = Queue<int>(int1_queue);

    //int_queue = double_queue;在沒有給定不同類型的對象之間的賦值運算符的重載函數時,編譯器會先調用不同類型對象的拷貝構造函數
    //將double類型的對象構造成Int類型的臨時對象,在調用相同類型對象之間的賦值運算符賦值給int_queue
    int_queue = Queue<double>(double_queue);
    int_queue.show();
    return 0;
}

運行結果:
Visual Leak Detector Version 2.4RC2 installed.
const Queue& 模板
int_queue——————————————
10 20
int1_queue—————————————-
10 20 40
double_queue————————————–
30.5
int2_queue—————————————-
30
賦值運算符的重載函數———————————————
operator Queue &src模板
30
No memory leaks detected.
Visual Leak Detector is now exiting.
請按任意鍵繼續…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章