创建包含链接列表和字符串的对象的链接列表时出现C ++错误

时间:2018-10-26 23:02:59

标签: c++ linked-list

在下面的程序中,我正在创建一个包含一个string和一个linkedlist<int>的对象。

由于obj中的main(),我仍然遇到未解决的问题。错误提示:

  

错误LNK2019:未解决的外部符号“ public:__thiscall   List :: List(class List const&)“   (“ 0?$ List @ H @@ QAE @ ABV0 @@ Z”)在函数“ public:__thiscall中引用”   Data :: Data(class Data const&)“(?? 0Data @@ QAE @ ABV0 @@ Z)

      main.cpp
            #include "List.h"
            #include <string>
            #include <iostream>
            #include <fstream>
            #include <utility> 
            using namespace std;

            template <class Object>
            void printList( const List<Object> & theList )  // SIMPLE PRINT FUNCTION
            {
                if( theList.isEmpty( ) )
                    cout << "Empty list" << endl;
                else
                {
                    ListItr<Object> itr = theList.first( );
                    for( ; !itr.isPastEnd( ); itr.advance( ) )
                        cout << itr.retrieve( ) << " ";
                }

                cout << endl;
            }

            class Data
            {
            public:

                Data(){
                    keyword = "";
                    List<int> pages;
                }

                void addNewData(string key, int article){

                    ListItr<int> pageitr = pages.zeroth();
                    keyword = key;
                    pages.insert(article, pageitr);

                }

                void addNewPage(int article){

                    ListItr<int> pageitr = pages.zeroth();
                    if(!pages.isExist(article))
                        pages.insert(article, pageitr);

                }


                bool operator==( const Data & rhs ){
                    if( this->keyword == rhs.keyword)
                    {
                        return true;
                    }
                    return false;
                }

                bool  operator!=( const Data & rhs ){
                    if( this->keyword != rhs.keyword )
                    {
                        return true;
                    }
                    return false;
                }

            private:
                string keyword;
                List<int> pages;

            };



            int main( )
            {
                List<Data> trialdata;
                ListItr<Data> dataItr;
                ifstream input;  
                string s,k;
                int count = 0;

                string filename = "docdb.txt"; 
                input.open(filename.c_str());

                if (input.fail() )
                {   cout << "could not open file " << filename << endl;
                return 0;
                }

                /*while(input >> s){
                input >> k;
                addtoList(s, stoi(k), *trialdata);

                }*/


                return 0;
            }

与此主体相关的标头称为List.h。它来自我的课程幻灯片。我添加了一个功能,并在没有创建对象的情况下对其进行了测试。工作正常。因此,我认为我的对象存在无法在链接列表中创建链接列表的问题。

#ifndef LIST_H
#define LIST_H
using namespace std; 
#include <iostream>

template <class Object>
class List;     // Incomplete declaration.

template <class Object>
class ListItr;     // Incomplete declaration.

class  BadIterator {
public:
    BadIterator() {}
};


template <class Object>
class ListNode
{
    ListNode( const Object & theElement = Object( ),           
        ListNode * n = NULL )
        : element( theElement ), next( n ) { }

    Object   element;
    ListNode *next;

    friend class List<Object>;
    friend class ListItr<Object>;
};

template <class Object>
class ListItr
{
public:
    ListItr( ) : current( NULL ) { }
    bool isPastEnd( ) const
    { return current == NULL; }
    void advance( )
    { if( !isPastEnd( ) ) current = current->next; }
    const Object & retrieve( ) const
    { if( isPastEnd( ) ) throw BadIterator();
    return current->element; }

private:
    ListNode<Object> *current;    // Current position

    ListItr( ListNode<Object> *theNode )
        : current( theNode ) { }

    friend class List<Object>; // Grant access to constructor
};

template <class Object>
class List
{
private:
    ListNode<Object> *header;

public:
    List( ){
        header = new ListNode<Object>;
    }
    List( const List & rhs );
    ~List( )        {
        makeEmpty( );  // Get rid of all list nodes
        delete header;  // then get rid of the header
    }

    bool isEmpty( ) const{  // see if the header  point to NULL 
        return header->next == NULL;
    }
    void makeEmpty( ){
        while( !isEmpty( ) )
            remove( first( ).retrieve( ) );
    }
    ListItr<Object> zeroth( ) const{
        return ListItr<Object>( header );
    }
    ListItr<Object> first( ) const{
        return ListItr<Object>( header->next );
    }
    void insert( const Object & x, const ListItr<Object> & p ){
        if( p.current != NULL )
            p.current->next = new ListNode<Object>( x, p.current->next );
    }
    ListItr<Object> find( const Object & x ) const{
        ListNode<Object> *itr = header->next; // Initialize

        while( itr != NULL && itr->element != x )
            itr = itr->next;

        return ListItr<Object>( itr );
    }

        bool isExist( const Object & x ) const{
        ListNode<Object> *itr = header->next; // Initialize

        while( itr != NULL){
            if(itr->element == x)
                return true;
            itr = itr->next;
        }
        return false;
    }


    ListItr<Object> findPrevious( const Object & x ) const{
        ListNode<Object> *itr = header;

        while((itr->next != NULL) && itr->next->element != x )
            itr = itr->next;

        return ListItr<Object>( itr );
    }
    void remove( const Object & x ){
        ListItr<Object> p = findPrevious( x );

        if( p.current->next != NULL )
        {
            ListNode<Object> *oldNode = p.current->next;
            p.current->next = p.current->next->next;  // Bypass deleted node
            delete oldNode;
        }
    }

    const List & operator=( const List & rhs ){
        if( this != &rhs )
        {
            makeEmpty( );

            ListItr<Object> ritr = rhs.first( );
            ListItr<Object> itr = zeroth( );
            for( ; !ritr.isPastEnd( ); ritr.advance( ), itr.advance( ) )
                insert( ritr.retrieve( ), itr );
        }
        return *this;
    }

};

#endif

2 个答案:

答案 0 :(得分:1)

您的标头为List模板声明一个复制构造函数:

template<class Object>
class List
{
    // ...
    List( const List & rhs );

但是,此副本构造函数未在任何地方定义。

因此,您的编译器在编译此转换单元时将假定模板实例将在另一个转换单元中定义并发出外部符号引用。而且由于没有在任何地方定义复制构造函数,因此您的程序无法链接。

由于缺少模板方法实例化,编译器报告的错误是经典的未定义符号错误。

您需要为此模板in your header file实现并定义副本构造函数。

答案 1 :(得分:1)

声明了 List的副本构造函数,但是您没有实现它:

template <class Object>
class List
{
    ...
public:
    ...
    List( const List & rhs ); // <-- DECLARATION ONLY!
    ...
};

链接器抱怨找不到List(const List &)的实现(在复制Data成员时,由编译器生成的pages的副本构造函数调用该实现1 )。

通常的做法是使用副本构造函数实现副本分配运算符,例如:

template <class Object>
class List
{
    ...    
public:
    ...

    List( const List & src ){
        header = new ListNode<Object>;
        ListItr<Object> sitr = src.first( );
        ListItr<Object> itr = zeroth( );
        for( ; !sitr.isPastEnd( ); sitr.advance( ), itr.advance( ) )
            insert( sitr.retrieve( ), itr );
        }
    }

    ...

    List& operator=( const List & rhs ){
        if( this != &rhs )
        {
            List<Object> temp(rhs);
            std::swap(temp.header, header);
        }
        return *this;
    }
    ...
};

1:顺便说一句,根本不需要您的Data()默认构造函数。 std::string有其自己的默认构造函数,因此您对Data::keyword成员的初始化是多余的,并且该构造函数正在声明一个名为{{1的未使用的 local List变量}}遮盖了pages成员。由于Data:::pages也具有默认构造函数,因此无需尝试显式初始化List成员。