【问题标题】:How to implement a doubly linked list that accommodates integers and void pointers?如何实现容纳整数和空指针的双向链表?
【发布时间】:2020-05-25 09:31:44
【问题描述】:

我正在尝试实现我自己的通用数据结构版本来改进我的编码。我有一个任务需要一个可以保存int 和空指针void * data 的双向链表。我的结构有两种成员类型,一种用于int,一种用于void*

struct Node {
    int data;
    void* pntData;
    Node* next;
    Node* previous;
};
class LL {
private:
    Node* head;
    Node* tail;
    int size;
public:
    LL();
    void insert_front(int data);
    void insert_front(void* data);//overloaded for void pointer data types
    void printLL();//removed unrelated methods
};

这是我的 Node 结构和双向链表类。我已经能够编写处理int 的所有方法。我的困惑在于将 void 指针作为参数并将其添加到具有 int 值的同一个链表中。

我知道 void 指针是一个可以指向任何类型数据的指针,但我很困惑我应该如何将 void 指针作为参数并将其添加到我初始化的同一个链表中使用此构造函数:

LL::LL() {
    head = nullptr;
    tail = nullptr;
    size = 0;
}

这是我的附加函数,我有重载的想法,这样如果参数是指针,数据将作为void* pntData 添加到我的类变量中。如果参数是 int,则数据将作为 int 添加到我的类变量中。

void LL::insert_front(int data) {
    Node* temp = new Node();
    if (head == nullptr) {
        head = temp;
        temp->previous = nullptr;
        temp->next = nullptr;
        temp->data = data;
        tail = temp;
    }
    else {
        temp->previous = nullptr;
        temp->next = head;
        temp->data = data;
        head->previous = temp;
        head = temp;
    }
    size++;
}

void LL::insert_front(void* data) {
    Node* temp = new Node();
    if (head == nullptr) {
        head = temp;
        temp->previous = nullptr;
        temp->next = nullptr;
        temp->pntData = data;
        tail = temp;
    }
    else {
        temp->previous = nullptr;
        temp->next = head;
        temp->pntData = data;
        head->previous = temp;
        head = temp;
    }
    size++;
}

问题可能在于我的printLL() 函数,它可能需要一个 if/else 来确定是需要打印 int 还是需要打印 void* pntData

请指点我正确的方向。

【问题讨论】:

  • 对你来说“正确的方向”是一本涵盖现代 C++ 的 C++ 书籍;特别是关于如何使用std::variant 模板的章节,它完全可以满足您的要求。它会让你的程序更简单,就像只需要一个insert_front(),而不是痛苦的代码重复。读完,再多练习,你应该可以完成这个“在线作业”。祝你好运!
  • 我认为将链接列表模板化为值类型可能更具教育意义,即编写一个包含 Node<T> 类的通用 LinkedList<T>。然后,您可以使用保存整数的链表和(单独的)void 指针。
  • 这似乎不是一个好的练习。如果您不存储有关指针指向的类型的信息,那么在容器中存储void* 指针是没有意义的,但这是一项相当困难的任务,实际上您只需使用std::variant 或(很少) std::any 改为类型通用容器的元素类型。
  • 如果元素是void*,您希望printLL() 打印什么?存储在指针中的地址还是指针指向的东西?您是否希望列表接受一个空指针作为有效值来存储void*
  • 虽然我同意你的看法,但这是我必须完成的任务。所以我不能将 void 指针存储在 Node 结构中而不同时存储类型?

标签: c++ linked-list void-pointers


【解决方案1】:

根据您希望printLL() 打印void* 指针指向的对象。

那是不可能的。 void* 指针没有关于它所指向的类型的信息,因此您无法取消引用该指针。

如果你想这样做,那么你需要在Node 中存储一个指向处理函数的附加指针,printLL() 将调用每个Node 来打印它的void*。然后你需要在指针类型上制作insert_*函数模板,这样你就可以找出正确的函数指针来存储提供的类型,即:

struct Node {
    int data;
    void* pntData;
    Node* next;
    Node* previous;
    void(*print)(void*) = nullptr; // Initialize with null pointer to indicate that no `void*` is stored.
};

//...

template<typename T>
void LL::insert_front(T* data) {
    Node* temp = new Node();
    //...
    temp->print = [](void* ptr){
        if(ptr != nullptr)
            std::cout << *static_cast<T*>(ptr);
        else
            // What to do if we stored a null pointer for `void*`
    };
    //...
}

//...

void LL::printLL() {
    //...
    if(node->print != nullptr)
        node->print(node->pntData);
    //...
}

我有一种感觉,这不是练习想要你做的,但正如我在 cmets 中所说的,这对我来说首先没有意义。

【讨论】:

  • 列表应该包含整数和指针。您可以根据需要添加其他类型。包括以下成员函数: void insert_front(int data ); void insert_front(void *data ); void insert_rear(int data ); void insert_rear(void *data); int remove_front_i( ); void * remove_front_p( ); int remove_rear_i( ); b> void * remove_rear_p( ); int empty( ); 使用动态内存。插入时使用“new”指令分配内存,删除时使用delete指令返回内存。
  • @Suede printLL 的规格是什么?
  • 这就是说明,您的回答看起来很有帮助。我将在晚饭后不久返回。非常感谢您的帮助,当我来到 Java 时,void 指针让我感到困惑。
  • @Suede 在 C++ 中你几乎不需要void*。它在 C 语言中更为常见。这就是练习如此混乱的原因。这不是 C++ 通常的编写方式。如果您不需要 printLL 并且该列表应该只与赋予它的 same 指针类型一起使用,那么您不需要我在回答中写的内容。正是 printLL 函数(或任何其他需要该类型的函数)使其难以实现。如果你不需要这个功能,那么你可以只存储一个额外的bool,表明你是存储一个int还是void*
  • @Suede 遗憾的是,这经常发生。在某些时候将 C++ 作为 C 的扩展进行教学是有道理的,但现代 C++ 的惯用风格与 C 非常不同,如果 教 C 或实际的现代 C++ 从开始,因为将两者混合会使一切变得不必要地复杂,就像您自己在这里看到的那样。 (虽然它是针对老师的,而不是针对学生的,但例如 this good CppCon talk 关于这个问题。)
猜你喜欢
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 2016-05-24
相关资源
最近更新 更多