0

这个问题之前可能已经回答过,但是经过两天的搜索,我找不到解决方案。

我制作了一个堆栈类,其中存储__data

class __data
{
private:
    void* __p;
    __datatype __type;

public:
    __data(void);
    __data(int i);
    __data(double d);
    __data(char* s);
    __data(void (*f)(Stack));

    bool IsFunction(void);
    bool IsInteger(void);
    bool IsNumber(void);
    bool IsString(void);

    void* Get(void);
};

我创建了这个类,因为堆栈将能够存储字符串、函数(指向函数的指针)、双精度数和整数。

问题是当我将整数或双精度压入堆栈然后弹出它并获取指向数据的指针(void* Get(void))时,我通过打印出它的值来调试它,因此我基本上有这个:

void print(Stack s)
{
    __data d = s.Pop();

    if (d.IsNumber()) // BUG: never the number I pass to __data
        std::cout << "IsNumber - " << *((double*)d.Get()) << std::endl;
    else if (d.IsInteger()) // BUG: it always prints out 1
        std::cout << "IsInteger - " << *((int*)d.Get()) << std::endl; // 
    else if (d.IsString())
        std::cout << "IsString - " << (char*)d.Get() << std::endl;
    else if (d.IsFunction())
    {
        std::cout << "IsFunction - " << d.Get() << std::endl;
        ((void (*)(Stack))d.Get())(s); // calls the function
    }
}

我不知道可能出了什么问题,也许是我分配的方式__p(返回的指针Get()),这些是__data整数和双精度的构造函数:

__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i;
}
__data::__data(double d)
{
    __type = _dt_number;
    __p = &d;
}

所以基本上我的问题是当我尝试获取返回的整数或双精度时,void*它要么给我一个1(整数)或2.13171e-314(双精度)值。

感谢您抽出宝贵的时间,如果已经有答案,我们很抱歉。

编辑:

我将重写 Stack 类并改用联合。这似乎是实现我的目标的最佳方法。

4

5 回答 5

1
__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i; // this only stores the address of i on the stack
}

你需要的是

__data::__data(int* i) // have the caller pass the address of their i
{
    __type = _dt_integer;
    __p = i; // this stores what you need
}
于 2012-07-16T12:59:36.577 回答
1

您的问题是您保存了临时对象的地址。例如:在本例中,您保存临时的地址double d

__data::__data(double d)
{
    __type = _dt_number;
    __p = &d;
}

该对象仅存在于当前范围(函数)中,之后该地址将无用,因为它很可能被堆栈中的其他内容覆盖。

我建议的解决方案是制作一个动态分配的副本:

__data::__data(double d)
{
    __type = _dt_number;
    __p = new double(d);
}

这将创建一个对象,该对象将一直存在,直到您手动释放指针delete。您应该在以下析构函数中执行以下操作__data

__data::~__data()
{
    delete __p;
}

更新:我强烈建议您不要char *用作字符串类型,而是使用 C++ 等效的std::string. 您也可以查看 library boost::any,它基本上与您想要实现的功能相同,但使用模板代替。

于 2012-07-16T13:01:10.227 回答
1
__data::__data(int i) 
{
    __type = _dt_integer;
    __p = &i; 
}
__data::__data(double d) 
{
    __type = _dt_number;
    __p = &d; 
}

因为你得到一个指向局部变量的指针

于 2012-07-16T13:02:29.380 回答
1
__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i;
}

你不能那样做!函数返回后该变量i不存在,因此任何指向它的指针都将包含垃圾。您必须将存储在i您的__data类中,而不是其地址。您(至少)有两种方法:使用多态性(__data为每种数据类型定义一个子类),或在内部声明一个联合__data,其中包含您支持的每种数据类型的成员。

于 2012-07-16T13:04:29.327 回答
0

变量 i 和 d 仅在函数 __data(int i)、__data(double d) 的生命周期内有效。我的意思是这些变量被创建到当前堆栈中并在退出函数时被删除,因此您存储一个指向变量的指针,该指针在程序运行的整个过程中都将无效。调用 Get 函数时,您会访问一个指向“死”变量的指针。

您应该将这些成员添加到您的班级。

class __data
{
private:
  int iInt;
  double dDouble;
}

并修改您的函数...以存储值而不是地址...

__data::__data(int i)
{
    __type = _dt_integer;
    iInt = i;
}
__data::__data(double d)
{
    __type = _dt_number;
    dDouble = d;
}

不要忘记修改 Get 函数。

void* __data::Get()
{
  switch( __type )
  {
    case _dt_integer:
      return (void*)iInt;
      break;
    case _dt_number:
      return (void*)dDouble;
      break;
  }

  return (void*)0;
}

那么你可以如下使用它。

cout << "Int value " << (int)d.Get();
cout << "double value " << (double)d.Get();

这是一种做你想做的事但唯一的方法!您可以使用联合成员来存储值,以节省内存使用量。

于 2012-07-16T13:08:58.693 回答