没有继承的链表[重复]

Posted

技术标签:

【中文标题】没有继承的链表[重复]【英文标题】:linked list without inheritance [duplicate] 【发布时间】:2019-04-13 12:54:02 【问题描述】:

我在 C++ 中创建了一个链表。首先我创建了一个类Node,然后创建了另一个类List。我的程序运行完美。问题是,我不明白为什么 NodeList 之间没有继承,以便 List 类可以访问 Node 的公共方法。 我做了一些更改,并从Node 及其工作中派生了List。那么它如何在有继承和没有继承的情况下运行呢?

#include <iostream>
#include <stdlib.h>

using namespace std;

/* The Node class */
class Node

private:
    int object;
    Node * nextNode;

public:
//mutator and Accessor for Node values
    void set(int object)
    
        this->object = object;
    
    int get()
    
        return object;
    

//mutator and Accessor for Node Address
    void setNext(Node * nextNode)
    
        this->nextNode = nextNode;
    
    Node * getNext()
    
        return nextNode;
    
;


/* The List class */
class List : public Node

private:
    int size;   // List Size ( number of nodes )
    Node * headNode;    // address of starting node of list
    Node * currentNode; // address of Current node of list
    Node * lastCurrentNode; // address of previous node of list

public:
    /* Constructor */
    List()
    
        headNode = new Node();          // creating new node and store its address in headNode  as its start of list
        headNode->setNext(NULL);    // the headNode is not connecting to any other node
        currentNode = NULL;             // as theres only head node so currentNode is empty
        lastCurrentNode = NULL;      //  Previous Node is also empty because there's only headNode
        size = 0;                               // Lisrs Size = 0 because theres no Value/data/object inside the list
    

    /* add() class method */
add (int addObject)

    Node * newNode = new Node();    // creating/adding new node and store its address in newNode Pointer
    newNode->set(addObject);           // Add Value/data/object in the node just created

    if( currentNode != NULL )   // at first time when Current Node pointer is not pointing to any node in the list
    
        newNode->setNext(currentNode->getNext());   // get adddress of node where current node will go and store that in the nextNode Pointer which is now called by our new node pointer so the addres that currentNode had now os taken and given to the new node
        currentNode->setNext( newNode );                  // address of new node we just created is now stored in current node
        lastCurrentNode = currentNode;                      // move Lastcurrent node to the current node position
        currentNode = newNode;                                 //   move currentNode pointer to the newNode we created;
    
    // if current node is not pointing to any node (first time)
    else
    
        newNode->setNext(NULL);             // new node we created will not point to any other next node because there's no one
        headNode->setNext(newNode);     //  head node now is pointing to the new node we created
        lastCurrentNode = headNode;      // lastCurrent node is now position to headNode so we can go back
        currentNode = newNode;             // current node is now position to the new node we created
    
    size ++;        // as there's new new in the list increase its size to +1


/* get() class method */
    get()
    
        if (currentNode != NULL)
        return currentNode->get();      // if current node is not null give the value where the current node is
    

    /* next() class method */
    next()
    
        if (currentNode == NULL)
        
            return false;
        

        lastCurrentNode = currentNode;  // move lastCurent node tot he position of current node
        currentNode = currentNode->getNext();       // move current node to the next node

        if (currentNode == NULL || size == 0)
        
            return false;
        
        else
        
            return true;
        
    
friend void traverse(List list);
friend List addNodes();

;

/* Friend function to traverse linked list */
void traverse(List list)    // friend function will get the object of List class

    Node* savedCurrentNode = list.currentNode;  // create new node pointer and assign it the address of current node
    list.currentNode = list.headNode;                   // move current node to the headNode ( starting of the list)
    for(int i = 1; list.next(); i++)                               // while we dnt reached to the end of list or not get false from next function
    
        cout << "\n Element " << i << "  =  " << list.get();        // traverse every node and display its value
    
    list.currentNode = savedCurrentNode;            // after traversing the whole nodes in the list move the current node to the position where it was befor e


/* Friend function to add Nodes into the list */
List addNodes()

    List list;
    list.add(2);
    list.add(6);
    list.add(8);
    list.add(7);
    list.add(1);

    cout << "\n List size = " << list.size <<'\n';

    return list;


int main()

    List list = addNodes();
    traverse(list);

改编自 Asker 的评论:

任何人都可以解释一下“第二类如何能够使用第一类的public 方法,而没有继承它们?第二类是否不必从第一类派生,所以它可以指向基类(1st)的方法?

【问题讨论】:

NodeList 之间的继承关系意味着一个是另一个的类型。这将是一个奇怪的选择,因为列表通常包含一系列节点。 List 不是 NodeNode 当然不是 List 作为未来的提示,尽量不要过度注释您的代码。注释代码是一件好事。不要评论代码是不好的。过度评论代码也很糟糕。您应该出于文档目的和重要的功能/方法以及非常复杂的代码部分进行评论。例如:void add(int addObject) 真的不需要那个注释,很明显那个方法会添加。 Node * newNode = new Node(); 也很明显。您必须注释您的代码以帮助其他专业人士,而不是教新手。 如果(普通)代码需要cmets,不要写cmets而是重写代码。 【参考方案1】:

在这种情况下,继承是错误的tm。正如 cmets 中提到的,继承对“is-a”关系建模:

法拉利汽车 一辆梅赛德斯是一辆汽车......都有四个***和n 门。所以 一辆普通汽车四个***和n 车门,法拉利和梅赛德斯继承了这些。

但列表(容器)肯定不是节点。从您的代码中,列表将具有:

一个值int object ...列表的值是什么?没有意义。 指针nextNode ...列表的“下一个节点”是什么?另一个清单?没有意义。 函数set(int object)int get() ... 设置/获取什么?列表的价值?没有意义 函数setNext(Node * nextNode)Node* getNext() ...如上:什么是列表的“下一个节点”?没有意义。

您要应用的模式是组合,它模拟“具有”关系:

法拉利有一个方向盘 一辆梅赛德斯有一个方向盘 一般的汽车有一个方向盘

你的

列表有一个第一个节点。

。 o O(你的问题让我想起一位德国作家坚持认为WurstBrot 应该继承自WurstBrot,而Brot 又继承Supermarket [原文如此])

顺便说一句:您在问题中显示的代码不应编译。有几个函数缺少返回类型。

您应该遵守Liskov Substitution Principle 的规定,即

在计算机程序中,如果S 是[= 继承自] T 的子类型,则T 类型的对象可以替换为S 类型的对象(即@987654339 类型的对象@ 可以替换为子类型 S 的任何对象,而不会改变程序的任何所需属性(正确性、执行的任务等)。

至于你的代码,List 的 c-tor 已经让我迷惑了:

List()

    headNode = new Node();     // why does an empty list have a Node thats its head?
    headNode->setNext(NULL);   // that is something the c-tor of Node should do
    currentNode = NULL;        // not sure what currentNode is supposed to be
    lastCurrentNode = NULL;    // contradicts my assumption from above that lastCurrentNode
                               // was a pointer to the last node of the List;
                               // you created a first Node so the last node should be
                               // pointing to headNode
    size = 0; // hm. Now you say your list is empty but you created a Node?

【讨论】:

如果我们从稍微不同的方向来看这个问题,Liskov Substitution Principle,问题会更加突出。如果StreeringWheel 继承Car,那么SteeringWheel 必须在可以使用Car 的所有情况下都可用。这显然是无稽之谈。回到提问者的上下文,如果Node 继承自List,那么NodeList 必须在所有使用List 的地方都可以互换。 @user4581301 好点!您可能想编写自己的答案而不是破坏我的答案;p 已经开始了。在我发布该评论时,我的回答与你的相似度约为 80%。 @user4581301 很抱歉偷了你的 80% ;) 如果我现在偷了你的 20% 怎么办?

以上是关于没有继承的链表[重复]的主要内容,如果未能解决你的问题,请参考以下文章

链表12:链表中删除元素的8道题之三

剑指Offer:合并两个排序的链表25

c_cpp 从已排序的链表中删除重复值节点 - Hackerrank

剑指offer链表题的双指针法总结

链表又去重

链表又去重