之前可能已经回答过这个问题,但经过两天的搜索后我找不到解决方案。
我创建了一个存储__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类并使用union。这似乎是实现我的目标的最佳方法。
答案 0 :(得分: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
}
答案 1 :(得分: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
。您也可以查看库boost::any
,它基本上可以实现您想要实现的目标,但使用模板代替。
答案 2 :(得分:1)
__data::__data(int i)
{
__type = _dt_integer;
__p = &i;
}
__data::__data(double d)
{
__type = _dt_number;
__p = &d;
}
因为你得到一个指向局部变量的指针
答案 3 :(得分:1)
__data::__data(int i)
{
__type = _dt_integer;
__p = &i;
}
你做不到!函数返回后变量i
不存在,因此任何指向它的指针都将包含垃圾。您必须在i
课程中存储__data
的值,而不是其地址。您有(至少)两种方法:使用多态(为每种数据类型定义__data
的子类),或在__data
内声明一个包含您支持的每种数据类型的成员的联合
答案 4 :(得分: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();
这是一种做你想要的但是唯一的方法!您可以使用union成员来存储值,以节省内存使用量。