C++ 使用Void*指针的链表

C++ 使用Void*指针的链表,c++,pointers,void-pointers,C++,Pointers,Void Pointers,我想在C/C++中创建一个通用链表(不使用C++模板)。 我已经写了以下简单的程序,它的工作到现在还不错- typedef struct node { void *data; node *next; }node; int main() { node *head = new node(); int *intdata = new int(); double *doubledata = new double(); char *str = "a";

我想在C/C++中创建一个通用链表(不使用C++模板)。 我已经写了以下简单的程序,它的工作到现在还不错-

typedef struct node
{
    void *data;
    node *next;
}node;


int main()
{
   node *head = new node();

   int *intdata = new int();
   double *doubledata = new double();

   char *str = "a";
   *doubledata = 44.55;
   *intdata = 10;

   head->data = intdata;

   node *node2 = new node();
   node2->data = doubledata; 
   head->next = node2;

   node *node3 = new node();
   node3->data = str;
   node3->next = NULL;
   node2->next = node3;

   node *temp = head;
   if(temp != NULL)
   {
    cout<<*(int *)(temp->data)<<"\t";
    temp = temp->next;
   }
   if(temp != NULL)
   {
    cout<<*(double *)(temp->data)<<"\t";
    temp = temp->next;
   }
   if(temp != NULL)
   {
    cout<<*(char *)(temp->data)<<"\t";
    temp = temp->next;
   }
   return 0;
}
typedef结构节点
{
作废*数据;
节点*下一步;
}节点;
int main()
{
节点*头=新节点();
int*intdata=newint();
double*doubledata=新的double();
char*str=“a”;
*doubledata=44.55;
*intdata=10;
head->data=intdata;
node*node2=新节点();
node2->data=doubledata;
head->next=节点2;
node*node3=新节点();
node3->data=str;
node3->next=NULL;
node2->next=node3;
节点*温度=头部;
如果(温度!=NULL)
{

在C中,实现泛型的唯一方法是使用
void*
,正如您已经在做的那样。不幸的是,这意味着没有简单的方法来检索链接列表中元素的类型。您只需要知道它们。

在C中,实现泛型的唯一方法是使用
void*
,就像您已经在做的那样。不毫无疑问,这意味着没有简单的方法来检索链接列表中元素的类型。你只需要知道它们。

通用列表的全部要点是,你可以在其中存储任何内容。但你必须现实一些……你仍然需要知道你在列表中放置了什么。因此,如果你要在列表中放置混合类型,t这时,您应该考虑使用变体模式。即,提供多种类型的类型。下面是一个简单的变体:

typedef struct Variant
{
    enum VariantType
    {
        t_string,
        t_int,
        t_double
    } type;

    union VariantData
    {
        char*    strVal;
        int      intVal;
        double   doubleVal;
    } data;

} Variant;

然后,您可以告诉自己“我正在我的
void*
列表中存储指向变体的指针。这就是您在C中的操作方式。我假设您说“C/C”++"你的意思是你试图编写C代码,但是使用C++编译器。不要忘记C和C++是两种不同的语言,它们有一些重叠。尽量不要把它们放在一个单词里,就像它们是一种语言一样。< /P> < P>一个普通的列表的全部要点是你可以在其中存储任何东西。但是你必须要现实……你仍然是N。您需要知道您要在其中添加什么。因此,如果您要在列表中添加混合类型,那么您应该考虑使用变体模式。即,提供多个类型的类型。下面是一个简单的变体:

typedef struct Variant
{
    enum VariantType
    {
        t_string,
        t_int,
        t_double
    } type;

    union VariantData
    {
        char*    strVal;
        int      intVal;
        double   doubleVal;
    } data;

} Variant;

然后,您可以告诉自己“我正在我的
void*
列表中存储指向变体的指针。这就是您在C中的操作方式。我假设您说“C/C”++“你的意思是你试图编写C代码,但是使用C++编译器。不要忘记C和C++是两种不同的语言,它们有一些重叠。尽量不要把它们放在一个单词里,就像它们是一种语言一样。< /P> < P>内存中的数据解释方式对于不同的数据类型是完全不同的。”
假设一个32位内存块有一些数据。当您将其键入int或float时,它将显示不同的值,因为这两种类型都是以不同的协议存储的。当将一些数据保存在由void*类型的变量指向的内存中时,它不知道如何解释其内存块中的数据。因此,您需要键入它以指定所需的类型读取数据。

对于不同的数据类型,解释内存中数据的方式完全不同。

假设一个32位内存块有一些数据。当您将其键入int或float时,它将显示不同的值,因为这两种类型都是以不同的协议存储的。当将一些数据保存在由void*类型的变量指向的内存中时,它不知道如何解释其内存块中的数据。因此,您需要键入它以指定所需的类型这是有点像把抽屉里的刀叉粘在一起,但不是把刀放在一个槽里,而是在另一个槽里放叉,在第三个槽里放勺子,在中间的小缝里放茶匙,我们把它们粘在任何地方,把它们扔进地里,然后想知道为什么当你只是Stic时。把手伸进去拿东西,你不知道你会得到什么

< C++ >的全部要点是允许你声明模板和类“任意内容的事物”。因为上面的代码使用<代码>新< /C> >,它不会编译成C。所以没有必要让它保持非描述性指针(或者甚至把数据作为指针存储在第一位)。
模板结构节点
{
T数据;
节点*下一步;
node():下一个(0){};
};
不幸的是,如果你想在同一个列表中存储一组不同类型的数据,它仍然会变得更混乱。如果你想这样做,你需要在节点本身中有一些东西来指示你存储了什么

自从1985年我开始使用计算机以来,我已经在列表中做过几次了(可能在我找到工作之前也做过几次)。更多的时候,我在一个类似于
std::map
的文件中做过某种“我将存储任意数据”,其中一个名称连接到一些“内容”.每次我使用这种功能,都是因为我在编写类似于编程语言的东西(例如配置脚本、基本解释器、LisP解释器等),用它来存储可以有不同类型的“变量”(
int
double
string
)或者类似的。我在其他地方也看到过类似的事情,比如OpenGL的一些地方,返回的数据根据您的要求是不同的类型,并且内部存储必须“知道”类型是什么


但我研究过的所有链表、二叉树、哈希表等99%只包含一件事这是有点像把抽屉里的刀叉粘在一起,但不是把刀放在一个槽里,而是把叉子放在另一个槽里,把第三个槽里的勺子和中间的小槽里的茶匙粘在一起,只要把它们夹在里面,不管它们是在什么地方发生的。我想知道为什么你只是把手伸进去,挑一些东西
#include <iostream>
#include <list>

class Base
{
public:

    virtual void Print() = 0;
};

class Derived1 : public Base
{
public:

    virtual void Print()
    {
        std::cout << 1 << std::endl; // Integer
    }
};

class Derived2 : public Base
{
public:

    virtual void Print()
    {
        std::cout << 2.345 << std::endl; // Double
    }
};

class Derived3 : public Base
{
public:

    virtual void Print()
    {
        std::cout << "String" << std::endl; // String
    }
};

int main(void)
{
    // Make a "generic list" by storing pointers to a base interface
    std::list<Base*> GenericList;
    GenericList.push_back(new Derived1());
    GenericList.push_back(new Derived2());
    GenericList.push_back(new Derived3());
    std::list<Base*>::iterator Iter = GenericList.begin();
    while(Iter != GenericList.end())
    {
        (*Iter)->Print();
        ++Iter;
    }

    // Don't forget to delete the pointers allocated with new above.  Omitted in example

    return 0;
}