首页 > 解决方案 > 模板类函数的未定义错误

问题描述

我正在尝试实现一个类模板双链接列表。我曾经在这里上课 DoublyLinkde List 和 Double Node。并在这里实现了 inserts() 和 Display 函数。
谁能帮我成功插入和显示操作。
例如,我想使用插入功能插入数据,并希望使用显示功能来查看它。

下面是代码:我把这段代码写在 final.cpp 文件中

template <class ItemType> //Reminder this is a template class, implement the .cpp accordingly
class DoubleNode
{
public:
    DoubleNode();
    //default constructor, sets next_ and prev_ to nullptr
    DoubleNode(const ItemType &anItem, DoubleNode<ItemType> *nextNodePtr = nullptr, DoubleNode<ItemType> *previousNodePtr = nullptr); //Parameterized Constructor, sets item_ to anItem, next_ to nextNodePtr, prev_ to previousNodePtr

    void setItem(const ItemType &anItem)
    {

        item_=anItem;
    }

    void setPrevious(DoubleNode<ItemType> *previousNodePtr)
    {
        next_= previousNodePtr;
    }


    void setNext(DoubleNode<ItemType> *nextNodePtr)
    {
        prev_=nextNodePtr;

    }

    ItemType getItem() const
    {

        return item_;
    }

    DoubleNode<ItemType> *getNext() const
    {

        return next_;
    }

    DoubleNode<ItemType> *getPrevious() const
    {
        return prev_;

    }

private:
    ItemType item_;              //actual content of your node
    DoubleNode<ItemType> *next_; //pointer to the node that is after this node
    DoubleNode<ItemType> *prev_; //pointer to the node that is before this node
};



template <class ItemType>
class DoublyLinkedList
{
public:
    // DoublyLinkedList(); //default constructor, sets headPtr_ to null and itemCount_ to 0

    /*
        Copy constructor that will make an exact copy of the list parameter, aList.
        This will make a deep copy of the list in the given parameter.
        You must iterate through the callee list parameter and insert nodes from aList into the caller list (the current one that isn't the parameter)
    */
    // DoublyLinkedList(const DoublyLinkedList &aList);

    // ~DoublyLinkedList(); //destructor that calls the clear function
    int getSize()
    {

        return itemCount_;

    } //return itemCount_

    /* *
        * Description: finds the node at parameter pos
        * Pre: pos is a valid place in the list, otherwise nullptr will be returned
        * Post: returns a pointer to the node at pos
    * */
    DoubleNode <ItemType> *getAtPos(const int &pos) const
    {
        DoubleNode<ItemType>* curPtr=headPtr_;
        for(int skip=1; skip<pos; skip++)
            curPtr=curPtr->getNext();
        return curPtr;
    }

    DoubleNode<ItemType> *getHeadPtr() const
    {

        return headPtr_;
    } //return *headPtr_

    /* *
        * Description: inserts parameter item in caller list at parameter position
            *IMPORTANT: Position 1 is the first position, not 0
        * Pre: position is a valid place within the list, otherwise false will be returned
        * Post: returns true if the item has been inserted in the caller list
        * Handles edge case of an invalid position parameter
        * Case: Inserting into head of the list
        * Case: Inserting into rear of the list
        * Case: Inserting into a position that is not an extremity
    * */

    bool inserts(const ItemType &item, const int &position = 1)
    {
        bool ableToInsert=(position>=1)&&(position<=itemCount_+1);
        if(ableToInsert)
        {
            DoubleNode<ItemType>* newNodePtr=new DoubleNode<ItemType>(item);
            if(position==1)
            {
                newNodePtr->setNext(headPtr_);
                headPtr_=newNodePtr;
            }
            else   if(position==2)
            {

                DoubleNode<ItemType>* prevPtr=getAtPos(position-1);
                newNodePtr->setNext(prevPtr->getNext());
                prevPtr->setNext(newNodePtr);
            }

            else
            {
                DoubleNode<ItemType>* headPtr_=getHeadPtr();
                DoubleNode<ItemType>* node = new DoubleNode<ItemType>[1];
//      cout<<"test 31"<<endl;
                node->setItem(item);
                if(headPtr_ == nullptr)
                {
                    // cout<<"test 1"<<endl;
                    headPtr_ = node;
                    // cout<<"new node added(firstnode) !"<<endl;
                    return true;
                }
                DoubleNode<ItemType>* temp = headPtr_;
                DoubleNode<ItemType>* prev_;
                // cout<<"test 1 "<<temp->next_<<endl;
                while(temp->getNext() != nullptr)
                {
                    //cout<<"test NULL 1"<<endl;
                    prev_ = temp;
                    temp = temp->getNext();
                }
                temp->setNext(node);
                temp->setPrevious(prev_);
                //cout<<"new node added at back!"<<endl;
            }
            itemCount_++;
        }

        return ableToInsert;
    }

    /* *
        * Description: removes node at parameter position
            *IMPORTANT: Position 1 is the first position, not 0
        * Pre: position is a valid place within the list, otherwise false will be returned
        * Post: returns true if the item at position has been removed from the caller list
        * Handles edge case of invalid position parameter
        * Case: removing only node in list
        * Case: removing from the end
        * Case: removing from the beginning
        * Case: removing from a position that is not an extremity
    * */
    // bool remove(const int &position);

    // bool isEmpty() const; //returns true if itemCount_ is 0

    /* *
        * Description: removes all items from the caller list
        * Traverse through the linked list and delete each individual node
        * Post: no nodes remain in the list and itemCount_ is at 0
    * */
    // void clear();

    //Iteratively outputs the contents of the caller list on the console
    //Example "A B C D E"
    //Note how theres no space at the end
    void display() const
    {
//     cout<<"linked list is empty"<<endl;
        DoubleNode <ItemType>*headPtr_=getHeadPtr();
        if(headPtr_ == nullptr)
        {
            // cout<<"linked list is empty"<<endl;
            return;
        }
        // cout<<endl<<"----link list items------"<<endl;
        DoubleNode<ItemType>* temp = headPtr_;
        while(temp != nullptr)
        {
            // cout<<temp->item_<<" ooo| ";
            temp = temp->getNext();
        }
        //  cout<<endl<<"--------------------------"<<endl;
    }

    //Iteratively outputs the contents of the caller list backwards on the console
    //Example if we had A B C D E we would instead display "E D C B A"
    //  void displayBackwards() const;

    // Reverses the list such that if my list was A B C D it will now be D C B A
    // Remember to change both previous and next pointers
    // Will be tested with both display and displayBackwards, make sure you have those working
    //  void invert();

private:
    DoubleNode<ItemType> *headPtr_; //points to the first item in the linked list
    int itemCount_;                 //lists how many items are currently in the list
};

int main()
{
    DoublyLinkedList<int> dl;

    dl.inserts(4,3);
    dl.display();
}

标签: c++classc++11templates

解决方案


请查看带有注释的代码行和代码块// CHANGE HERE

变更摘要:

  1. 为 的构造函数添加了定义DoubleNode
  2. 更改setPrevious并且setNext使其正确设置next_prev_
  3. 添加了一个构造函数DoublyLinkedList和一个空析构函数(您可以稍后填充它)。
  4. 改变的逻辑inserts
  5. 稍微改display了一下功能。
  6. 改变了main功能。请注意,inserts返回 abool但您没有检查返回值。

PS 仔细检查这个修改过的代码,并尝试了解做了哪些更改。此外,当某些东西不起作用时,您必须检查逻辑,使用调试器或简单的打印语句调试代码并修复任何错误。

#include <iostream>

template <class ItemType> //Reminder this is a template class, implement the .cpp accordingly
class DoubleNode
{
public:
    //default constructor, sets next_ and prev_ to nullptr
    // CHANGE HERE
    DoubleNode() : next_(nullptr), prev_(nullptr)
    {
    }
    
    //Parameterized Constructor, sets item_ to anItem, next_ to nextNodePtr, prev_ to previousNodePtr
    // CHANGE HERE
    DoubleNode(const ItemType &anItem, DoubleNode<ItemType> *nextNodePtr = nullptr, DoubleNode<ItemType> *previousNodePtr = nullptr)
    : next_(nextNodePtr), prev_(previousNodePtr), item_(anItem)
    {
    }

    void setItem(const ItemType &anItem)
    {

        item_=anItem;
    }

    void setPrevious(DoubleNode<ItemType> *previousNodePtr)
    {
        // CHANGE HERE
        prev_ = previousNodePtr;
    }


    void setNext(DoubleNode<ItemType> *nextNodePtr)
    {
        // CHANGE HERE
        next_ = nextNodePtr;

    }

    ItemType getItem() const
    {

        return item_;
    }

    DoubleNode<ItemType> *getNext() const
    {

        return next_;
    }

    DoubleNode<ItemType> *getPrevious() const
    {
        return prev_;

    }

private:
    ItemType item_;              //actual content of your node
    DoubleNode<ItemType> *next_; //pointer to the node that is after this node
    DoubleNode<ItemType> *prev_; //pointer to the node that is before this node
};



template <class ItemType>
class DoublyLinkedList
{
public:
    //default constructor, sets headPtr_ to null and itemCount_ to 0
    // CHANGE HERE
    DoublyLinkedList() : headPtr_(nullptr), itemCount_(0)
    {    
    }

    /*
        Copy constructor that will make an exact copy of the list parameter, aList.
        This will make a deep copy of the list in the given parameter.
        You must iterate through the callee list parameter and insert nodes from aList into the caller list (the current one that isn't the parameter)
    */
    // DoublyLinkedList(const DoublyLinkedList &aList);

    //destructor that calls the clear function
    // CHANGE HERE
    ~DoublyLinkedList()
    {
    }
    
    int getSize()
    {
        return itemCount_;
    }

    /* *
        * Description: finds the node at parameter pos
        * Pre: pos is a valid place in the list, otherwise nullptr will be returned
        * Post: returns a pointer to the node at pos
    * */
    DoubleNode <ItemType> *getAtPos(const int &pos) const
    {
        DoubleNode<ItemType>* curPtr = headPtr_;
        for (int skip = 1; curPtr != nullptr && skip < pos; skip++)
            curPtr = curPtr->getNext();
        return curPtr;
    }

    DoubleNode<ItemType> *getHeadPtr() const
    {
        return headPtr_;
    }

    /* *
        * Description: inserts parameter item in caller list at parameter position
            *IMPORTANT: Position 1 is the first position, not 0
        * Pre: position is a valid place within the list, otherwise false will be returned
        * Post: returns true if the item has been inserted in the caller list
        * Handles edge case of an invalid position parameter
        * Case: Inserting into head of the list
        * Case: Inserting into rear of the list
        * Case: Inserting into a position that is not an extremity
    * */

    bool inserts(const ItemType &item, const int &position = 1)
    {
        bool ableToInsert = (position >= 1) && (position <= itemCount_ + 1);
        if (ableToInsert)
        {
            DoubleNode<ItemType>* newNodePtr = new DoubleNode<ItemType>(item);
            if (position == 1)
            {
                //newNodePtr->setNext(headPtr_);    // CHANGE HERE
                headPtr_ = newNodePtr;
            }
            else    // CHANGE HERE
            {
                if (headPtr_ == nullptr)
                {
                    std::cout << "ERROR: cannot insert at position " << position << ", head is nullptr\n";
                    return false;
                }
                DoubleNode<ItemType>* prevPtr = getAtPos(position - 1);
                // CHANGE HERE
                DoubleNode<ItemType>* prevNextPtr = prevPtr->getNext();
                prevPtr->setNext(newNodePtr);
                newNodePtr->setPrevious(prevPtr);
                newNodePtr->setNext(prevNextPtr);
                if (prevNextPtr)
                    prevNextPtr->setPrevious(newNodePtr);
            }

            // CHANGE HERE
            /*else
            {
                DoubleNode<ItemType>* headPtr_ = getHeadPtr();
                // CHANGE HERE
                DoubleNode<ItemType>* node = new DoubleNode<ItemType>(item);
                // CHANGE HERE
                if (headPtr_ == nullptr)
                {
                    std::cout << "ERROR: cannot insert at position " << position << ", head is nullptr\n";
                    return false;
                }
                
                DoubleNode<ItemType>* prevNode = getAtPos(position - 1);
                
                if(headPtr_ == nullptr)
                {
                    // cout<<"test 1"<<endl;
                    headPtr_ = node;
                    // cout<<"new node added(firstnode) !"<<endl;
                    return true;
                }
                DoubleNode<ItemType>* temp = headPtr_;
                DoubleNode<ItemType>* prev_;
                // cout<<"test 1 "<<temp->next_<<endl;
                while(temp->getNext() != nullptr)
                {
                    //cout<<"test NULL 1"<<endl;
                    prev_ = temp;
                    temp = temp->getNext();
                }
                temp->setNext(node);
                temp->setPrevious(prev_);
                //cout<<"new node added at back!"<<endl;
            }*/
            itemCount_++;
        }
        
        return ableToInsert;
    }

    /* *
        * Description: removes node at parameter position
            *IMPORTANT: Position 1 is the first position, not 0
        * Pre: position is a valid place within the list, otherwise false will be returned
        * Post: returns true if the item at position has been removed from the caller list
        * Handles edge case of invalid position parameter
        * Case: removing only node in list
        * Case: removing from the end
        * Case: removing from the beginning
        * Case: removing from a position that is not an extremity
    * */
    // bool remove(const int &position);

    // bool isEmpty() const; //returns true if itemCount_ is 0

    /* *
        * Description: removes all items from the caller list
        * Traverse through the linked list and delete each individual node
        * Post: no nodes remain in the list and itemCount_ is at 0
    * */
    // void clear();

    //Iteratively outputs the contents of the caller list on the console
    //Example "A B C D E"
    //Note how theres no space at the end
    // CHANGE HERE
    void display() const
    {
//     cout<<"linked list is empty"<<endl;
        DoubleNode <ItemType>*headPtr_=getHeadPtr();
        if(headPtr_ == nullptr)
        {
            std::cout << "linked list is empty" << std::endl;
            return;
        }
        // cout<<endl<<"----link list items------"<<endl;
        DoubleNode<ItemType>* temp = headPtr_;
        while (temp != nullptr)
        {
            std::cout << temp->getItem() << " | ";
            temp = temp->getNext();
        }
        std::cout << std::endl << "--------------------------" << std::endl;
    }

    //Iteratively outputs the contents of the caller list backwards on the console
    //Example if we had A B C D E we would instead display "E D C B A"
    //  void displayBackwards() const;

    // Reverses the list such that if my list was A B C D it will now be D C B A
    // Remember to change both previous and next pointers
    // Will be tested with both display and displayBackwards, make sure you have those working
    //  void invert();

private:
    DoubleNode<ItemType> *headPtr_; //points to the first item in the linked list
    int itemCount_;                 //lists how many items are currently in the list
};

int main()
{
    DoublyLinkedList<int> dl;

    // CHANGE HERE
    bool ret = dl.inserts(4, 1);
    ret = ret && dl.inserts(5, 2);
    ret = ret && dl.inserts(6, 3);
    ret = ret && dl.inserts(7, 4);
    ret = ret && dl.inserts(8, 2);
    ret = ret && dl.inserts(9, 4);
    if (!ret) {
        std::cout << "Insert failed\n";
        return 1;
    }
    dl.display();
}

推荐阅读