【问题标题】:Pointer, Class and void* in C++C++ 中的指针、类和 void*
【发布时间】:2011-05-18 18:33:08
【问题描述】:

我得到了斐波那契堆的代码。此代码使用以下函数来比较两个键:

int
cmp(void *x, void *y)
{
    int a, b;
    a = (int)x;
    b = (int)y;

    if (a < b)
        return -1;
if (a == b)
        return 0;
    return 1;
}

这是可行的,因为 KEY 当前是一个 INT 数字。

我想修改此代码以使用我的名为“Node”的类。这个类已经实现了操作符、=。

我在代码中的改编是:

Node a, b   // instead int a, b
a = (Node)x;
b = (Node)y;

但我得到了错误:

dijkstra.cpp:168: error: no matching function for call to 'Node::Node(void*&)'
graph.h:39: note: candidates are: Node::Node()
graph.h:39: note:                 Node::Node(const Node&)

我也试过了:

Node a, b   // instead int a, b
a = (Node*)x;
b = (Node*)y;

并得到错误:

dijkstra.cpp:168: error: no match for 'operator=' in 'a = (Node*)x'
graph.h:39: note: candidates are: Node& Node::operator=(const Node&)

我放弃尝试设置值并解决问题如下:

int cmp(void *x, void *y)
{ 
    if ((Node*)x < (Node*)y)
        return -1;
    if ((Node*)x == (Node*)x)
        return 0;
    return 1;
}

我想了解我在前面的示例中做错了什么。

提前致谢。

【问题讨论】:

  • cmp 函数将指针转换为整数(显然假设它们的大小相同),然后比较指针。不是指向的值。这毫无意义!
  • 致downvoter:我不明白你为什么这样做,但指针是一个困难的概念,并且 void-pointer 与它值得的类混合。
  • @博人:初始代码我没有INT值??
  • 我是反对者,我告诉过你原因。 :-) 使用void* 很糟糕,因为我们看不到它们应该是什么。转换为其他类型并没有帮助。你想做什么?
  • @Bo Person:我知道 void* 不好。但是我得到了一段斐波那契堆的代码,代码用来抽象比较的方式就是这样。现在我必须交付这个,但将来我将使用模板进行修复。但是,感谢您提供的信息。

标签: c++ class void-pointers


【解决方案1】:

更改以下几行

a = (Node*)x;
b = (Node*)y;

a = *( (Node*) x); 
// type cast from void* to Node* and then fetch the contents by dereferencing the pointer.

b = *( (Node*) y);

您只是将指针从void* 类型转换为Node* 并尝试将指针分配给Node 类型的变量。

【讨论】:

  • 由于OP使用的是C++,我认为他可以使用static_cast,而不是C风格的演员。
  • 我想这问了我的问题。我会用这个做一些测试。
  • 我会改用引用/指针,避免不必要的对象复制……
【解决方案2】:

您说您为 Node 类重载了运算符(

int
cmp(void *x, void *y)
{
    Node *a, *b;
    a = (Node*)x;
    b = (Node*)y;

    if (*a < *b)
        return -1;
    if (*a == *b)
        return 0;
    return 1;
}

【讨论】:

    【解决方案3】:

    看起来您正在调用 cmp 函数(或通过回调调用)并引用 Node 对象。如果是这种情况,您可以将代码更改为

    Node& a = static_cast<Node&>(*x);
    Node& b = static_cast<Node&>(*y);
    

    我在没有查看调用代码的情况下猜测这一点 - 老实说,这不是一个好主意。如果您也可以发布调用代码,将有助于更好地回答问题。

    【讨论】:

      【解决方案4】:

      没有理由比较 (Node*) 或 (void*) 值 - 这只是指针,您将比较内存地址。看起来你只需要实现operator =

      【讨论】:

        【解决方案5】:

        除了 yasouser 所说的,您的第一个程序将无法按预期运行。

        a = *(int*)x; b = *(int*)y;

        【讨论】:

          【解决方案6】:

          首先关于您的 cmp 函数本身: 通常人们只实现operator&lt;;在实现operator&gt; 时,通常是通过对已实现的operator&lt; 进行反向参数调用。您的 cmp 实现还需要 Node 实现 operator==,这可能是不必要的。

          此外,如果您的函数接受 void* 但在内部将它们转换为 NODE* 并取消引用它们并且它使用通用“cmp”命名,则会出现一个小问题。

          更好的实现是这样的:

          int NodeCmp(void *x, void *y)
          { 
          // handle NULL pointers here
              if (*(Node*)x < *(Node*)y)
                  return -1;
              if (*(Node*)y < *(Node*)x)
                  return 1;
              return 0;
          }
          

          如果您愿意,您可能需要研究 std::less 或模板函数。

          【讨论】:

            【解决方案7】:

            通常,当您将void* 传递给函数时,您必须将指针转换为您想要的类型的另一个指针。例如:

            void func(void* a, void* b)
            {
                int* c, d;
                c = (int*)a;
                d = (int*)b;
                //... continue rest of function
            }
            

            另一方面,您在编写时试图初始化T 类型的对象

            (T)value;
            

            T(value);
            

            这就是为什么您会抱怨没有为 T 类型的对象提供正确的构造函数类型。

            您应该做的是转换为T* 类型的指针,然后取消引用这些新转换的指针以在实际对象之间进行您想要的任何比较 类型为T。例如(假设 T 是您想要比较的某种所需类型......即,这不是模板):

            int cmp(void* a, void* b)
            {
                T* c, d;
                c = (T*)a;
                d = (T*)b;
            
                if (*c < *d)
                    return -1;
                else if (*c > *d)
                    return 1;
                else
                    return 0;
            }
            

            【讨论】:

              猜你喜欢
              • 2012-07-01
              • 1970-01-01
              • 2020-08-12
              • 2019-12-05
              • 2011-04-01
              • 1970-01-01
              相关资源
              最近更新 更多