模板类函数的未定义错误

Posted

技术标签:

【中文标题】模板类函数的未定义错误【英文标题】:undefined error to template class function 【发布时间】:2021-12-20 00:46:09 【问题描述】:

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

下面是代码:我把这段代码写在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();

【问题讨论】:

请打破有问题的部分并创建一个minimal reproducible example。然后详细描述问题。您期望的结果是什么?您的实施会产生什么结果? DoubleNode 构造函数没有被定义,只是被删除了。 setPrevious 设置next_setNext 设置prev_ @kiner_shah 你能写下代码吗?因为我听不懂你说什么 @MirRahat, DoubleNode 构造函数刚刚声明(它们以分号; 结尾),它们各自的函数体在哪里?并查看您的 setPrevioussetNext 函数。 @kiner_shah 你能告诉我 setPrevious 和 setNext 函数吗?我的意思是我必须做什么? 【参考方案1】:

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

变更摘要:

    DoubleNode 的构造函数添加了定义。 更改了setPrevioussetNext,以便正确设置next_prev_。 为DoublyLinkedList 添加了一个构造函数和一个空的析构函数(以后可以填充)。 更改了inserts 的逻辑。 稍微更改了display 函数。 更改了main 函数。请注意,inserts 返回 bool,但您没有检查返回值。

P。 S. 非常仔细地检查修改后的代码,并尝试了解进行了哪些更改。此外,当某些东西不起作用时,您必须检查逻辑,使用调试器或简单的打印语句调试代码并修复任何错误。

#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();

【讨论】:

以上是关于模板类函数的未定义错误的主要内容,如果未能解决你的问题,请参考以下文章

typedef和模板的未定义符号? [复制]

模板实现顺序表

自定义 CMDIChildWndEx 模板类链接错误

为啥我在将 unique_ptr 返回给模板类的对象的函数定义时出现错误?

如何定义派生模板类的功能?

error C2953: 类模板已经定义