重载运算符以添加两个双向链表

时间:2014-11-06 08:59:27

标签: c++

我需要帮助重载“+”运算符,以便将两个双向链接列表相加。由于得到“不匹配operator = ...”错误,我无法编译我的程序。我已经重载了'='运算符,但很难打印添加到std输出的结果。我也重载了<<运营商。一直试图弄清楚什么是错误的几个小时没有成功。任何提示如何解决这个问题和/或解决方案都是非常受欢迎的。这是我的OOP课程的作业。 提前谢谢!

编辑:代码背后的基本思想是复制集合。重载运算符'+'应该作为联合使用,'*'作为交集。我很难将联合正确打印到std输出。 '+ ='似乎工作正常。 '<<'效果也不错,但只有在打印单个列表时才会有效。


编辑: 编译器产生的错误(g ++,代码:: blocks的输出,我已经删除了编译器注释):

llist3.cpp|149|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note:   no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|151|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note:   no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|152|error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka       std::basic_ostream<char>}’ and ‘LList’)|

   #include<iostream>
using namespace std;

class LList {
public:
    struct Node {
        int elem;
        Node* succ;
        Node* prev;
        Node() : succ(0), prev(0), elem(0) {}
    };
    LList();
    LList(LList& list);
    ~LList();

    Node* next();
    Node* begin()  { curr = head; }

    int getElem() { return curr->elem; }
    void addElem(int elem);
    LList operator+(LList& set);
    LList operator+(int elem);
    LList& operator+=(LList& set);
    LList& operator+=(int elem);
    LList& operator=(LList& list);
    friend ostream& operator<<(ostream& os, LList& obj);
 private:
    Node* curr;
    Node* head;
    Node* tail;
    int size;
    void pushFront(Node* n);
    void pushInside(Node* n);
    void pushBack(Node* n);
};

LList::LList() : head(0), tail(0), size(0), curr(0) {}
LList::LList(LList& list) : size(0), curr(0), head(0), tail(0) {
    list.curr = list.head;
    while(list.curr) {
        addElem(list.getElem());
        list.next();
    }
}
LList::Node* LList::next() {
    if (curr)
        return (curr = curr->succ);
    else
        return 0;
}
void LList::addElem(int elem) {
    Node* n = new Node;
    n->elem = elem;
    if (curr) {
        if (curr == head && elem < curr->elem) {
            pushFront(n);
        }
        else if (elem > curr->elem) {
            curr = curr->succ;
            addElem(elem);
        }
        else if (elem < curr->elem && elem > (curr->prev)->elem) {
            pushInside(n);
        }
        else if (elem < curr->elem) {
            curr = curr->prev;
            addElem(elem);
        }
    } else {
        pushBack(n);
    }
}
void LList::pushFront(Node* n) {
    head = n;
    n->succ = curr;
    curr->prev = n;
    n->prev = 0;
    curr = n;
    size++;
}
void LList::pushInside(Node* n) {
    (curr->prev)->succ = n;
    n->succ = curr;
    n->prev = curr->prev;
    curr->prev = n;
    size++;
}
void LList::pushBack(Node* n) {
    if (!head) {
        head = n;
    } else {
        tail->succ = n;
        n->prev = tail;
    }
    tail = n;
    curr = n;
    size++;
}
LList::~LList() {
    for (curr = head; curr;) {
        Node* temp = curr->succ;
        delete curr;
        curr = temp;
    }
}
LList& LList::operator=(LList& list) {
    list.begin();
    if (this != &list) {
        for (curr = head; curr;) {
            Node* temp = curr->succ;
            delete curr;
            curr = temp;
        }
        while (list.curr) {
            addElem(list.getElem());
            list.next();
        }
    }
    return *this;
}
ostream& operator<<(ostream& os, LList& list) {
    LList::Node* p = list.head;
    os << "{ ";
    while(p) {
        os << p->elem << (p->succ ? ", " : "");
        p = p->succ;
    }
    os << " }" << endl;
    return os;
}
LList LList::operator+(LList& set) {
    LList temp = *this;
    temp += set;
    return temp;
}
LList LList::operator+(int elem) {
    *this += elem;
    return *this;
}
int main() {
    LList setA;
    setA.addElem(1234);
    setA.addElem(1435);
    setA.addElem(1100);
    LList setB;
    setB.addElem(1234);
    setB.addElem(1435);
    setB.addElem(5100);
    setB = setA + 1234; // 1st error here
    LList setD;
    setD = setA + setB; //2nd
    cout << setA + setB << endl; //3rd
}

2 个答案:

答案 0 :(得分:2)

您的代码中存在一个明显的错误:

Node* begin()  { curr = head; }

此代码调用未定义的行为,因为您没有返回值。它应该是这样的:

Node* begin()  { curr = head; return curr; }

此外,您应该在不更改LList参数的函数中通过const引用传递LList

例如:

LList::LList(LList& list);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);

应该是:

LList::LList(const LList& list);
LList& operator=(const LList& list);
friend ostream& operator<<(ostream& os, const LList& obj);

请更改这些和其他函数以传递const引用。如果您想了解为什么要更改此设置,如果您尝试执行此操作,则会立即看到问题:

LList list1;
LList list2;
//...
std::cout << list1 + list2;

operator <<正在寻找非const LList对象,但添加“inline”会返回一个临时LList(这意味着返回值为const })。由于您的重载operator <<只接受非const LList,代码将无法编译。

因此,您需要将operator <<中的参数更改为const LList&

答案 1 :(得分:0)

您的列表类中有一个内置的“当前”指针。这是一个严重的设计错误。由于此错误,您无法正确定义函数。

这是一个设计错误,因为使用此设计,您无法迭代const列表,这意味着,除了其他不好的事情之外,您无法对临时列表执行任何有用的操作。所以当你计算setA + setB时,你不能将它分配给任何东西,因为要分配你需要迭代,所以你需要一个非{const}参数到operator=和复制构造函数。但是你不能将临时绑定到非const引用。

即使您绕过复制构造函数和复制赋值运算符中的公共接口,并直接复制列表而不使用curr,任何必须使用公共接口的用户函数都会遇到同样的问题。也就是说,setA + setB将不能用作函数参数。您需要先将其分配给某个变量,然后将该变量传递给该函数。

您也无法获取列表并在迭代过程中将其传递给某个函数,并期望继续从您离开的位置进行迭代,因为迭代列表的任何内容都会更改curr指针。

最好的解决方案是摆脱curr成员并完成大部分论证const LList&。虽然这不是onky解决方案,但是将当前指针内置到列表类中还有许多其他缺点,所以我不会谈论它们。

为了迭代列表,你必须提供一个可以在列表上来回转换的单独对象,以及一个可以在 const 列表上来回转换的单独变体。这被称为迭代器,如果你想在C ++中做任何事情,你需要阅读这个概念。

在您的情况下,迭代器可以是Node*const Node*。您只需要提供返回列表中第一个节点的成员函数,这些函数已经存在。真正的图书馆也这样做。由于各种原因,它们通常将节点指针包装在单独的迭代器类中;但是对于一个简单的作业,这是没有必要的(尽管你可以这样做)。