c++ - << 使用继承和模板定义

标签 c++ templates visual-studio-2012 linked-list

<分区>

我正在尝试使用模板在 C++ 中实现链表。不幸的是,当我尝试使用 ostream 时遇到 Unresolved external 错误。本站类似问题的解答说是头文件和.cpp文件不匹配,我觉得这里不是。谁能帮我解决这个问题,我真的需要掌握这一点。

链表.h:

#ifndef LINKEDLIST_H
#define LINKEDLIST_H

#include <string>
#include <iostream>

template<class T> class LinkedList;

// Class representing a templated linkedlist element
template<class T> class LLElement {
    friend class LinkedList<T>;
public:
    // Constructor
    LLElement(T* p_Data) : data(p_Data), next(NULL) {}

    T* getData() const { return data; }
    LLElement<T>* getNext() { return next; }
private:
    LLElement<T>* next;
    T* data;
};

// Class representing a templated linked list
template<class T> class LinkedList {
public:
    LinkedList() : size(0), start(NULL) {}
    LinkedList(const LinkedList&);
    ~LinkedList();

    unsigned int getSize() const { return size; }
    LLElement<T>* getStart() const { return start; }

    //adds shallow copy of T to the LinkedList
    void sortedAdd(T*);
    //removes the first occurence of T from the LinkedList
    void remove(T*);
    //merges existing LinkedList with given LinkedList
    void merge(const LinkedList<T>&);
    //formatted print of LinkedList to given outputstream
    void showLinkedList(std::ostream& p_Out) const;
    friend std::ostream& operator<<(std::ostream& outputStream, const LinkedList<T>& sec);

private:
    LLElement<T>* start;
    unsigned int size;
};

//LinkedList copy constructor
//TODO
template<class T>  LinkedList<T>::LinkedList(const LinkedList<T>& a){
    this->size=a.getSize();
    this->start=a.getStart();
}

// LinkedList destructor
// TODO
template<class T> LinkedList<T>::~LinkedList(){
    LLElement<T>* a=this->getStart();
    LLElement<T>* b=a->next;
    while(a!=NULL){
        delete a;
        a=b;
        b=a->next;
    }

}


// sortedAdd
// adds shallow copy of T to the LinkedList
// TODO
template<class T> void LinkedList<T>::sortedAdd(T* add){
    LLElement<T>* a=new LLElement<T>(add);
    LLElement<T>* b=this->getStart();
    while(!(*(b->data)<=*(a->getData()))){
        b=b->next;
    }
    a->next=b->next;
    b->next=a;
    this->size++;
}



// remove
// removes the first occurence of T from the LinkedList
// TODO
template<class T> void LinkedList<T>::remove(T* ab){
    LLElement<T>* a=this->getStart();
    LLElement<T>* b=this->getStart();
    while(a!=NULL){
        if(*(a->data)==*(ab)){
            if(b==a){
                this->start=a->next;
                delete a;
                this->size--;
                return;
            }
            b->next=a->next;
            delete a;
            this->size--;
            return;
        }
        b=a;
        a=b->getNext();
    }
}


// TODO output operator

template<class T>  std::ostream& operator<<(std::ostream& outputStream, const LinkedList<T>& sec){
    sec.showLinkedList(outputStream);
    return outputStream;
}
//merges existing LinkedList with given LinkedList
template<class T> void LinkedList<T>::merge(const LinkedList<T>& p_LL){
    LLElement<T> *cursor = p_LL.start;
    while (cursor != NULL){
        sortedAdd(cursor->data);
        cursor = cursor->next;
    }
}

//formatted print of LinkedList to given outputstream
template<class T> void LinkedList<T>::showLinkedList(std::ostream& p_Out) const {
    LLElement<T>* current = start;
    int counter = 1;
    p_Out << "LINKEDLIST OF SIZE " << size << std::endl;
    while (current != NULL){
        p_Out << "LL ELEMENT " << counter++ << " : ";
        p_Out << *(current->getData()) << std::endl;
        current = current->getNext();
    }
}

#endif

错误:

Error   2   error LNK2019: unresolved external symbol "class
std::basic_ostream<char,struct std::char_traits<char> > & __cdecl
operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class
LinkedList<class CMSContent> const &)" (??6@YAAAV?$basic_ostream@DU
$char_traits@D@std@@@std@@AAV01@ABV?$LinkedList@VCMSContent@@@@@Z) referenced in function "public: void __thiscall CMS::print(void)" (?print@CMS@@QAEXXZ)   C:\Users\knudde\Documents\Visual Studio 2012\Projects\Ex1314\Ex1314\CMS.obj Ex1314

也许 CMSContent 有问题?

内容.h:

#ifndef H_CONTENT
#define H_CONTENT

#include <map>
#include <set>
#include <iostream>
#include <string>

enum ACCESSRIGHT { owner, modify, read, none };

class CMSContent {
public:
    CMSContent(std::string p_Id, std::string p_Username);

    void addPermissionUser(ACCESSRIGHT p_Right, std::string p_Username);
    ACCESSRIGHT getAccessright(std::string p_Username);

    std::string getIdentifier(){ return identifier; };
    virtual std::string serialise() const=0;
    bool CMSContent::operator< (const CMSContent& param) const;
    bool CMSContent::operator<= (const CMSContent& param) const;
    bool CMSContent::operator== (const CMSContent& param) const;
    friend std::ostream& operator<<(std::ostream& outputStream, CMSContent& secondOperand);
protected:
    std::string identifier;
    std::map<ACCESSRIGHT, std::set<std::string> > accessrightsByRank;
    //map with key accessright and value set of usernames with given access right
private:
    void setIdentifier(std::string p_Id){ identifier = p_Id; };
    bool userHasHigherAccessRight(ACCESSRIGHT p_Right, std::string p_Username);
    void removeLowerAccessRights(ACCESSRIGHT p_Right, std::string p_Username);

    static int uniqueID;
};

class Project : public CMSContent {
public:
    Project(std::string p_Name, std::string p_Description, std::string p_Username);

    virtual std::string serialise() const;

    std::string getProjectdescription(){ return projectdescription; };
    void setProjectdescription(std::string p_Description){ projectdescription = p_Description; };
protected:
    std::string projectdescription;
};

class Document : public CMSContent {
public:
    Document(std::string p_Name, std::string p_Username, std::string p_URL);
    virtual std::string serialise() const;

    std::string getURL(){ return URL; };
    void setURL(std::string p_Url){ URL = p_Url; };
protected:
    std::string URL;
};

class HowTo : public CMSContent {
public:
    HowTo(std::string p_Subject, std::string p_Howto_content, std::string p_Username);
    virtual std::string serialise() const;

    std::string getHowto_content() { return howto_content; }
    void setHowto_content(std::string p_Howto_content) { howto_content = p_Howto_content; }
protected:
    std::string howto_content;
};

#endif

内容.cpp:

#include "Content.h"
#include <sstream>

CMSContent::CMSContent(std::string p_Id, std::string p_Username) : identifier(p_Id){
    accessrightsByRank[owner].insert(p_Username); 
}

void CMSContent::addPermissionUser(ACCESSRIGHT right, std::string p_Username) { 
    if (!userHasHigherAccessRight(right, p_Username)){
        removeLowerAccessRights(right, p_Username);
        accessrightsByRank[right].insert(p_Username);
    }
}

bool CMSContent::operator< (const CMSContent& param) const{
    return (this->identifier.compare(param.identifier)<0);
}

bool CMSContent::operator<= (const CMSContent& param) const{
    return (this->identifier.compare(param.identifier)<=0);
}

bool CMSContent::operator== (const CMSContent& param) const{
    return (this->identifier.compare(param.identifier)==0);
}

std::ostream& operator<<(std::ostream& outputStream,  CMSContent& cont){
    outputStream<<cont.serialise();
    outputStream<<"owner = ";
    std::set<std::string>::iterator a,b;
    a=cont.accessrightsByRank[owner].begin();
    b=cont.accessrightsByRank[owner].end();
    while(a!=b){
        outputStream << (*a) <<std::endl;
    }
        outputStream<<"modify = ";

    a=cont.accessrightsByRank[modify].begin();
    b=cont.accessrightsByRank[modify].end();
    while(a!=b){
        outputStream << (*a) <<std::endl;
    }
    outputStream<<"read = ";

    a=cont.accessrightsByRank[read].begin();
    b=cont.accessrightsByRank[read].end();
    while(a!=b){
        outputStream << (*a) <<std::endl;
    }
    return outputStream;
}

bool CMSContent::userHasHigherAccessRight(ACCESSRIGHT right, std::string p_Username){
    //TODO
    if(right==owner){return false;}
    std::map<ACCESSRIGHT, std::set<std::string> >::iterator beg, end;
    std::set<std::string> ::iterator beg1, end1;
    beg=accessrightsByRank.begin();
    end=accessrightsByRank.find(right);
    while(beg != end){
        beg1=(*beg).second.begin();
        end1=(*beg).second.end();
        while(beg1!=end1){
            if((*beg1).compare(p_Username)==0){
                return true;
            }
            beg1++;
        }
        beg++;
    }
    return false;
}

void CMSContent::removeLowerAccessRights(ACCESSRIGHT right, std::string p_Username){
    //TODO
    std::map<ACCESSRIGHT, std::set<std::string> >::iterator beg, end;
    std::set<std::string> ::iterator beg1, end1;
    end=accessrightsByRank.end();
    beg=accessrightsByRank.find(right)++;
    while(beg != end){
        beg1=(*beg).second.begin();
        end1=(*beg).second.end();
        while(beg1!=end1){
            if((*beg1).compare(p_Username)==0){
                (*beg).second.erase(beg1);
                return;
            }
            beg1++;
        }
        beg++;
    }
}

Project::Project(std::string p_Identifier, std::string p_Description, std::string p_Username) : CMSContent("P;"+p_Identifier, p_Username){
    projectdescription = p_Description; 
}

std::string Project::serialise() const {
    std::stringstream output;
    output << "Project name = " << identifier << std::endl;
    output << "Project description = " << projectdescription << std::endl;
    return output.str();
}

Document::Document(std::string p_Identifier, std::string p_Username, std::string p_URL) : CMSContent("D;"+p_Identifier, p_Username){ 
    URL = p_URL;
}

std::string Document::serialise() const {
    std::stringstream output;
    output << "Document name = " << identifier << std::endl;
    output << "Document URL = " << URL << std::endl;
    return output.str();
}

HowTo::HowTo(std::string p_Identifier, std::string p_Howto_content, std::string p_Username) : CMSContent("H;"+p_Identifier, p_Username){ 
    howto_content = p_Howto_content; 
}

std::string HowTo::serialise() const{
    std::stringstream output;
    output << "Howto subject = " << identifier << std::endl;
    output << "Howto content = " << howto_content << std::endl;
    return output.str();
}

最佳答案

删除 friend std::ostream& operator<<(std::ostream& outputStream, const LinkedList<T>& sec);来自 LinkedList 类定义。您已经在此 header 中拥有此类运算符的模板化版本,并且链接器告诉您非模板化版本缺少实现。 链表.h:

#ifndef LINKEDLIST_H
#define LINKEDLIST_H

#include <string>
#include <iostream>

template<class T> class LinkedList;

// Class representing a templated linkedlist element
template<class T> class LLElement {
    friend class LinkedList<T>;
public:
    // Constructor
    LLElement(T* p_Data) : data(p_Data), next(NULL) {}

    T* getData() const { return data; }
    LLElement<T>* getNext() { return next; }
private:
    LLElement<T>* next;
    T* data;
};

// Class representing a templated linked list
template<class T> class LinkedList {
public:
    LinkedList() : size(0), start(NULL) {}
    LinkedList(const LinkedList&);
    ~LinkedList();

    unsigned int getSize() const { return size; }
    LLElement<T>* getStart() const { return start; }

    //adds shallow copy of T to the LinkedList
    void sortedAdd(T*);
    //removes the first occurence of T from the LinkedList
    void remove(T*);
    //merges existing LinkedList with given LinkedList
    void merge(const LinkedList<T>&);
    //formatted print of LinkedList to given outputstream
    void showLinkedList(std::ostream& p_Out) const;
    //friend std::ostream& operator<<(std::ostream& outputStream, const LinkedList<T>& sec);

private:
    LLElement<T>* start;
    unsigned int size;
};

//LinkedList copy constructor
//TODO
template<class T>  LinkedList<T>::LinkedList(const LinkedList<T>& a){
    this->size=a.getSize();
    this->start=a.getStart();
}

// LinkedList destructor
// TODO
template<class T> LinkedList<T>::~LinkedList(){
    LLElement<T>* a=this->getStart();
    LLElement<T>* b=a->next;
    while(a!=NULL){
        delete a;
        a=b;
        b=a->next;
    }

}


// sortedAdd
// adds shallow copy of T to the LinkedList
// TODO
template<class T> void LinkedList<T>::sortedAdd(T* add){
    LLElement<T>* a=new LLElement<T>(add);
    LLElement<T>* b=this->getStart();
    while(!(*(b->data)<=*(a->getData()))){
        b=b->next;
    }
    a->next=b->next;
    b->next=a;
    this->size++;
}



// remove
// removes the first occurence of T from the LinkedList
// TODO
template<class T> void LinkedList<T>::remove(T* ab){
    LLElement<T>* a=this->getStart();
    LLElement<T>* b=this->getStart();
    while(a!=NULL){
        if(*(a->data)==*(ab)){
            if(b==a){
                this->start=a->next;
                delete a;
                this->size--;
                return;
            }
            b->next=a->next;
            delete a;
            this->size--;
            return;
        }
        b=a;
        a=b->getNext();
    }
}


// TODO output operator

template<class T>  std::ostream& operator<<(std::ostream& outputStream, const LinkedList<T>& sec){
    sec.showLinkedList(outputStream);
    return outputStream;
}
//merges existing LinkedList with given LinkedList
template<class T> void LinkedList<T>::merge(const LinkedList<T>& p_LL){
    LLElement<T> *cursor = p_LL.start;
    while (cursor != NULL){
        sortedAdd(cursor->data);
        cursor = cursor->next;
    }
}

//formatted print of LinkedList to given outputstream
template<class T> void LinkedList<T>::showLinkedList(std::ostream& p_Out) const {
    LLElement<T>* current = start;
    int counter = 1;
    p_Out << "LINKEDLIST OF SIZE " << size << std::endl;
    while (current != NULL){
        p_Out << "LL ELEMENT " << counter++ << " : ";
        p_Out << *(current->getData()) << std::endl;
        current = current->getNext();
    }
}

#endif

此外,关于 Content.h:

bool CMSContent::operator< (const CMSContent& param) const;
bool CMSContent::operator<= (const CMSContent& param) const;
bool CMSContent::operator== (const CMSContent& param) const;

应该是

bool operator< (const CMSContent& param) const;
bool operator<= (const CMSContent& param) const;
bool operator== (const CMSContent& param) const;

关于c++ - << 使用继承和模板定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30593043/

相关文章:

c++ - 这是 C++ 中的有效删除操作吗?

c++ - 指针和非指针类型的重载 -> 运算符

c++ - 使用类型特征为字符串迭代器专门化模板函数

c++ - 禁止模板虚函数是一种不必要的谨慎吗?

angularjs - 在 Azure 服务器 Hot Towel Angular 上获取元数据查询失败错误 Breeze/Breeze/元数据

c++ - 独立于平台的资源系统(如 Qt 资源系统)

c++ - 什么导致内存保留

symfony - 如何从父包扩展 Twig 模板?

entity-framework - 将 EF Code First 同步到 SQL Azure

visual-studio - Visual Studio 中的多项选择?