【问题标题】:Link List of Class, How to get call toString while Transversing?类的链接列表,如何在遍历时调用 toString?
【发布时间】:2016-03-18 01:00:57
【问题描述】:

我想知道如何在 BoxClass 类的链接列表中调用 toString() 方法。 BoxClass 有一个 double lengthwidthheight

我的 BoxClass:

class BoxClass{
private:
    double length;
    double width;
    double height;

public:
    // Default constructor w/ no parameters
    BoxClass(){
        length = 0;
        width = 0;
        height = 0;
    }

    // Constructor with arguments
    BoxClass(double boxLength, double boxWidth, double boxHeight){
        length = boxLength;
        width = boxWidth;
        height = boxHeight;
    }

    // Setters and Getters
    void setLength(double boxLength){
        length = boxLength;
    }
    double getLength(){
        return length;
    }

    void setWidth(double boxWidth){
        width = boxWidth;
    }
    double getWidth(){
        return width;
    }

    void setHeight(double boxHeight){
        height = boxHeight;
    }
    double getHeight(){
        return height;
    }

    // Returns the volume of the boxes
    double Volume(){
        return (length * width * height);
    }

    // toString method for boxes, returns "(length) x (width) x (height) string
    string toString(){
        return ("(" + to_string(length)+ "x" + to_string(width) + "x" + to_string(height) + ")");
    }
}; // End of BoxClass() class

LinkNode.h

//Template ListNode class definition.
#ifndef LINKNODE_H
#define LINKNODE_H

template <typename T> class LinkList;

template <typename T> class LinkNode{
friend class LinkNode <T>; 
public:
    LinkNode(const T &); 
    T getData()const;
    T data;
    LinkNode <T> *nextPtr;
};

template <typename T> LinkNode <T>::LinkNode(const T &info):data(info), nextPtr(NULL){
    // Empty body
}

template <typename T>T LinkNode<T>::getData()const{
    return data;
}

#endif

Main(创建类,将其添加到链接列表

//  Create the Box class
    BoxClass userBox(length, width, height);

//  Add box class to Link List
    Box.insertNode(userBox);

    Box.print();

LinkList.h print() 方法

template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;

if (isEmpty()) {
    cout << "No boxes in list!\n";
} else {
    LinkNode<T>*currentPtr = firstPtr;

    cout << "Your boxes in increasing order of volume is:\n";
    //      while (currentPtr) {
    while (currentPtr != NULL) {

        //      Output as "#. (length x width x height)
                cout << counter << ". " << currentPtr->data << endl;
        printf("  %i. %.2f\n", counter, currentPtr->data);
        currentPtr = currentPtr->nextPtr;
        counter++;
    }
}
}

LinkList.h

//Template LinkList class definition.
#ifndef LINKLIST_H
#define LINKLIST_H
#include <iostream>
#include "LinkNode.h"
using namespace std;

template<typename T> class LinkList {
public:
    LinkList();
    void addNode(const T &);
    void insertNode(const T &);
    bool isEmpty() const;
    void print() const;

private:
    LinkNode<T>*firstPtr;
    LinkNode<T>*getNewNode(const T &);
};

template<typename T>LinkList<T>::LinkList() :firstPtr(NULL) {
// Empty body
}

template <typename T>void LinkList<T>::insertNode(const T &value) {
LinkNode<T>*newPtr = getNewNode(value);
bool inserted = false;

if (isEmpty() || (newPtr->data < firstPtr->data)) {
    newPtr->nextPtr = firstPtr;
    firstPtr = newPtr;
    //      cout << "  " << newPtr->data << " inserted at front of list.\n";
    printf("  %.2f inserted at front of list.\n", newPtr->data);
} else {
    LinkNode<T>*currentPtr = firstPtr;
    while (currentPtr->nextPtr && !inserted) {
        if (newPtr->data < currentPtr->nextPtr->data) { 
            //      cout << " " << newPtr->data << " inserted before " << currentPtr->nextPtr->data << ". " << endl;
            printf("  %.2f inserted before %.2f.\n", newPtr->data, currentPtr->nextPtr->data);
            newPtr->nextPtr = currentPtr->nextPtr;
            currentPtr->nextPtr = newPtr;
            inserted = true;
        } else {
            currentPtr = currentPtr->nextPtr;
        }
    }
    if (!inserted) {
        currentPtr->nextPtr = newPtr;
        printf("  %.2f inserted at the end of list.\n", newPtr->data);
    }
}
}

template<typename T>bool LinkList<T>::isEmpty()const {
return firstPtr == NULL;
}

template<typename T>LinkNode<T>*LinkList<T>::getNewNode(const T &value) {
return new LinkNode<T>(value);
}

template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;

if (isEmpty()) {
    cout << "No boxes in list!\n";
} else {
    LinkNode<T>*currentPtr = firstPtr;

    cout << "Your boxes in increasing order of volume is:\n";
    //      while (currentPtr) {
    while (currentPtr != NULL) {

        //      Output as "#. (length x width x height)
                cout << counter << ". " << currentPtr->data << endl;
        printf("  %i. %.2f\n", counter, currentPtr->data);
        currentPtr = currentPtr->nextPtr;
        counter++;
    }
}
}

#endif

我的问题是——我该如何遍历列表并调用toString() BoxClass 方法?我尝试了cout &lt;&lt; data.toString() &lt;&lt; endl; 中的所有内容,但这不起作用。这几天一直卡在这个问题上,谁能帮帮我?

编辑:添加 LinkList.h

【问题讨论】:

  • 基本上,您的实现缺少iterator 的概念。从链表外部,我应该能够说“给我第一个节点”,然后“给我下一个节点”并循环。是的,您现在可以在内部 列表中执行此操作,但在公开场合,无法执行此操作。所以这就是你需要实现的。

标签: c++ list class hyperlink


【解决方案1】:

当您编写template &lt;typename T&gt; class LinkNode{ 时,您明确指出您的节点类将不具备其包含的节点类型的内置知识。

你没有向我们展示你的 LinkList&lt;T&gt; 类,但显然,同样的事情适用于它:因为它由 LinkNode&lt;T&gt; 组成,它还必须接受 &lt;T&gt; 类型的泛型参数,所以它不能构建- 了解&lt;T&gt; 的实际类型。

因此,您不能突然引入具有此类知识的方法。它没有任何意义。 “它不计算”。

您需要做的是在其他地方添加您的print() 方法,并使其接受LinkList&lt;BoxClass&gt;。然后,它将能够将LinkNodes 视为LinkNode&lt;BoxClass&gt;,并能够调用linkNode.data.toString()

【讨论】:

  • 我觉得我不太明白...那么,问题出在我的节点上吗?你是说本质上,我的 Node 类只是不知道如何处理我的BoxClassmethod()?。如果是这样,这是否意味着我的 LinkNode.h 必须有一个 print() 方法,该方法接受 LinkList&lt;BoxClass&gt; 作为参数,这反过来又允许我调用 toString()
  • @user3499789 如果您不能使用public 接口遍历它,那么链表将毫无用处。如果我想对列表中的每个节点执行其他操作,而不是打印,该怎么办?如果不是打印,我想将数据保存到文件中,或者为列表中的每个节点保存更复杂的东西怎么办?您是否要知道链表类的用户可能想要对列表中的数据执行的所有操作?当然不是。所以你当前的实现是不完整的——它没有为链表类外部的代码提供一种方法来遍历每个节点。
  • 是的,这就是我要说的,除了“LinkNode.h”部分。 print() 方法不属于 LinkNode,也不属于 LinkList。它必须去其他地方。
【解决方案2】:

问题是LinkList&lt;T&gt; 类的实现无法让客户端代码循环遍历列表的每个节点。如果我们不想打印,而是对每个盒子做其他事情怎么办?

另外,如果我有一个LinkList&lt;Widget&gt; 会看起来很奇怪,当我打电话给print() 时会看到文字:

"您的箱子按体积升序排列是:";

我会说,“什么盒子?什么体积?我有小部件,而不是盒子”。

一个更完整的实现看起来像这样(警告:这还没有编译。它是为了给你你应该做什么的要点):

template<typename T> class LinkList {
public:
    LinkList();
    void addNode(const T &);
    void insertNode(const T &);
    bool isEmpty() const;

    // this is what you're missing from the current implementation
    typedef LinkNode<T>* Iterator;
    Iterator begin() { return firstPtr; }
    Iterator next(Iterator ptr) { return ptr->nextPtr; }
    Iterator end() { return NULL; }  

private:
    LinkNode<T>* firstPtr;
    LinkNode<T>* getNewNode(const T &);
};

那么,print 函数不需要是链表的一部分。它可以生活在外面:

LinkList<BoxClass> boxList;
//...
void print() 
{
    if (boxList.isEmpty()) 
        cout << "No boxes in list!\n";
    else
    {
       int counter = 1;
       cout << "Your boxes in increasing order of volume is:\n";

       // get first box
       LinkList<BoxClass>::Iterator curBox = boxList.begin();

       // loop until no more boxes 
       while (curBox != boxList.end())
       {
            // now use curBox to do whatever you want with this box
            BoxClass& b  = curBox->getData();  
            cout << counter << ". " << b.toString();

            // go to the next box
            curBox = boxList.next(curBox);
            counter++;
        }
    }
}

注意print 不再是LinkList 的成员。另外,请注意typedef,以便为客户端使用的LinkNode 指针提供一个“好听”的名称。 cmets 应该是不言自明的。

我不想通过引入“真正的”迭代器(即重载 ++)使代码过于复杂,但该运算符将替换 LinkList&lt;T&gt;:::next() 函数调用。我把它留给你作为一个额外的练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 1970-01-01
    • 2019-05-31
    • 2017-07-29
    相关资源
    最近更新 更多