C++继承设计链表

Posted

技术标签:

【中文标题】C++继承设计链表【英文标题】:C++ inheritance designing a linked list 【发布时间】:2009-12-02 18:56:21 【问题描述】:

我想创建一个从类 List 继承的链表类 ListList。 ListList 使用 List 中的函数,但有自己的函数。它有自己的指向列表开头的起始指针,以及拥有不同数量元素的 Node 结构。

但是,看起来,当从 ListList 调用 List 的函数之一时,List 使用它自己的起始指针和节点。但我希望使用 ListList 的起始指针和节点。 有人可以帮我解决这个问题吗? 我可以发布一些代码,但我不知道哪一部分是相关的......

这是我上面所说的列表

class LinkList

public:
LinkList(); //constructor that sets the start pointer to NULL, to show that the list is empty
~LinkList(); //destructor that deletes each node in the linked list
LinkList(const LinkList &original); //copy constructor
void addToken(string token); //creates a node with the given token and places it at the beginning of the linked list
string showList(); //returns a string of tokens, separated by commas and spaces
bool findToken(string token); //searches linked list for the given token, returns true if the token is in the list
string getToken(string word); //searches linked list for a token that begins with the given word.
                              //Returns the full token if there's a token that begins with the given word, else returns an empty string
void deleteList();
protected:

struct Node //each node of the linked list, held together by the next pointer

    string token;
    bool second_word; //tells whether or not there is a space within the token (a two-word keyword)
                      //This could be easily changed to an int that tells how many words are within the keyword (for multi-word keywords)
    Node *next; //pointer to the next node of the linked list. NULL if there is no next node
;

Node *start; //pointer to the beginning of the linked list, and the last added node
bool twoWordToken(string token); //returns true if there is a space located within a token, meaning the token consists of two words.
;

这是我上面叫ListList的那个

class LinkListList: public LinkList

public:
LinkListList(); //modified contructor initiates the pointers start and ptrNode
~LinkListList(); //modified destructor deletes all nodes and secondaryList nodes
LinkListList(const LinkListList &original); //copy constructor
bool addSubList(LinkList subList, string commandWord); //calls setPtrNode, then adds the given subList to that node
bool findSubToken(string commandWord, string token); //calls setPtrNode, then calls on that node's secondaryList's findToken function
                                                     //returns true if the findToken function returns true, else returns false
string showSubList(string commandWord); //returns a string of tokens, separated by commas and spaces, representing the subList of the given token
string getSubToken(string word, string commandWord); //searches commandWord's subList for a token that begins with the given word.
                                              //Returns the full token if there's a token that begins with the given word, else returns an empty string
private:

struct Node //each node of the linked list, held together by the next pointer

    string token;
    bool second_word; //tells whether or not there is a space within the token (a two-word keyword)
    LinkList secondaryList; //keeps a list of all related words
    Node *next;
;

Node *start; //pointer to the beginning of the linked list
Node *ptrNode; //this pointer is used for the functions
void setPtrNode(string token); //sets ptrNode to point to the node containing the specified token. ptrNode is NULL if the token could not be found  
;

【问题讨论】:

最有用的示例代码可能是定义 List 和 ListList 的头文件。 你需要发布类定义 您不只是使用 STL 列表有什么原因吗? 【参考方案1】:

编辑:我明白了。

理想情况下,您应该只有一个链表实现,它可以保存任何类型的值,包括——这里是最重要的——一个复合数据结构,它有一个链表作为其字段之一。在您现在拥有的代码中,据我所知,继承实际上是不必要的,您通常会重复创建链表的所有艰苦工作,并且您正在将链表数据结构与更高级别混合表示各种单词列表的对象。

这是我在这里构建数据结构的一种可能方式:

通用链表:

template <typename T>
class LinkedList  ... ;

一个使用链表来表示你正在创建的单词列表的类:

class TokenList 
  struct Token 
    string word;
    LinkedList<string> related;
  ;
  LinkedList<Token> list;
  // Methods to add/search/remove tokens from the lists and sublists
;

(另外,我怀疑您实际寻找的数据结构是 map,但这是另一个讨论。)

【讨论】:

ListList 已经启动,因为当我注释掉它时,它说它不能将 List 指针转换为 ListList 指针... ListList 有它自己的节点,就像父节点一样,除了它在每个节点中包含一个列表。这就是为什么我认为我首先可以做继承的事情。我认为它会成功,所以我可以让每个节点都包含一个列表,比如二维链表之类的。 template... 嗯...我可以在 Visual C++ 2005 中制作一个吗?我有一堂课,一本书到处都使用模板,但是老师说不要尝试(所以尝试通过撤消模板来学习这些东西是一堂很难的课)。我之前试过一个,但它不起作用......【参考方案2】:

看起来您正在寻找Has-A 关系而不是Is-A 关系。

我建议您的 LinkListList 使用第一种类型的列表列表,而不是使用继承。

【讨论】:

您需要将您的 LinkList 模板化(在此处阅读模板:en.wikipedia.org/wiki/Template_(programming))。然后你可以让 LinkListList 有一个字符串列表,比如: list > or, list> 等。希望思路很清楚:) 在您的情况下, ListOfLists 不是(不应该是)一个新类。它只是一个包含一堆其他列表的常规列表。当你试图用它来表达has_a situataion时,继承实际上是有害的。继承是为了实现is_a的情况而设计的:ThreadSafeList is_a List,但是它知道线程。如果您需要让列表包含其他列表,而不仅仅是元素,您可能需要查看模板。 @Arkadiy +1:我在某处读到(Sutter 和 Alexandrescu 的 C++ 编码风格?),一种推理方式是您继承现有代码可以使用您的新实现,而不是使用现有代码实施。存在 ThreadSafeList 以便使用 List 的现有代码可以安全地执行此操作,而问题代码正在继承以重用现有方法。【参考方案3】:

我认为您的 List 类需要一些虚函数。它对ListList一无所知,所以很难指望它使用派生类的成员。

【讨论】:

【参考方案4】:

基类中的虚函数允许继承者提供对它的覆盖。当基类(或将其视为基类的外部调用者)调用派生实例中的函数时,它知道在派生类中查找该覆盖而不是使用基类中的覆盖。

如果您控制基 List 类(而不是提供的框架类),您可以对其进行重构以在关键位置使用虚函数,以便派生 ListList 类可以将它们重定向到自己的逻辑,同时仍然可以访问代码访问它作为一个列表 - 例如,因此您可以创建一个 ListList 并将其传递给期望一个列表的东西。

但是如果你不能改变 List 并且它还没有你可以覆盖的虚函数,你可能做不到。您可能需要寻找不同的(较低的)基类,或者将 ListList(或 LinkedList?)创建为单独的类而不是派生类。它可以提供一个 ToList() 函数以将其内容导出为标准 List(以及一个构造函数,该构造函数采用 List 和/或 From(List) 函数从 List 导入回 ListList)。但以这种方式使用它可能需要做更多的工作,这取决于您实际上需要用它做什么,而您首先希望从 List 派生。

已编辑:使用您现在发布的代码,看起来继承可能不是您真正需要的,毕竟,正如@rmn 指出的那样。因此,虽然这个答案希望能稍微解释一下虚函数的工作原理(适用于最初提出的问题),但它可能不适用于您真正尝试对这两个类做的事情。

【讨论】:

我做了两个。那么,我可以说一些 List 函数是虚拟的,然后让两个类都可以正常工作而无需大量重写代码吗? 我想你想把 List 类(LinkList)变成一个通用列表(或模板,正如其他人所说),它可以收集不同类型的数据(统一或混合,取决于你的需要) )。然后,您可以为特定类型创建派生类,如果这有帮助的话,其中之一可能是列表列表。我不确定你已经拥有多少工作或重新编码。

以上是关于C++继承设计链表的主要内容,如果未能解决你的问题,请参考以下文章

算法链表链表相关问题总结

数据结构-链表链表的基本操作

数据结构-链表链表的相关算法

[11道链表经典笔试题]优化的算法思想:反转链表链表相交快慢指针

reorder-list——链表快慢指针逆转链表链表合并

何为链表链表示例以及翻转链表