将 void 指针转换为动态类型
Convert void pointer to a dynamic type
我正在尝试将 void 指针转换为动态类型。
例如,我将 double 变量传递给 test1
函数,我希望 sum 函数可以工作。但是我在 sum(*reinterpret_cast<myType*>(tmp))
上收到 C2664 无法转换参数错误。
如果我使用它,它将起作用。
double c= *reinterpret_cast<double*>(tmp);
sum(c);
我该如何解决这个问题?
void sum(double a)
{
cout << "sum:" << a+10 << endl;
}
void test1(void* tmp)
{
typedef decltype(tmp) myType;
sum(*reinterpret_cast<myType*>(tmp));
}
int main()
{
double a = 87.7;
test1(&a);
return 0;
}
首先,动态类型只有在使用继承时才真正有意义。例如,如果您有这样的代码:
class Base {};
class Derived : public Base {};
int main() {
Base *b = new Derived;
}
在这种情况下,b
的静态类型为 Base *
,但动态类型为 Derived *
(因为它被声明为指向 Base
的指针, 但实际上指向 Derived
).
的一个实例
因此,如果您想恢复实际的动态类型,您需要从定义一些基 class 和一些派生 class(es) 开始,并在它们之间进行转换。 When/if 你这样做,你通常想使用 dynamic_cast
而不是 reinterpret_cast
来完成这项工作(它会自动检查实际类型,所以如果你尝试转换,转换将失败到它不是真正指向的类型)。但在大多数情况下,您希望在基 class 中定义某种虚函数,并根据需要在派生 class 中覆盖它,因此您不需要使用 dynamic_cast
根本。另请注意,dynamic_cast
仅适用于包含至少一个虚函数的 classes(但如果您使用 public 继承而没有任何虚函数,则您可能做错了什么) .
或者,您基本上可以创建一个受歧视的联盟。您需要存储一些东西来记录存储的实际类型,并且您将使用它在需要时转换回正确的类型。
enum type { FLOAT, DOUBLE };
struct value {
type t;
void *value;
};
float f = 1.2f
double d = 3.2;
value v { FLOAT, &f };
value y { DOUBLE, &d };
void do_call(value v) {
if (v.type == FLOAT) {
use_float(*reinterpret_cast<float *>(v.value));
else if (v.type == DOUBLE)
use_double(*reinterpret_cast<double *>(v.value));
}
但是,编译器不会在 void *
中存储任何内容来跟踪它真正指向的对象类型。如果你想从 void *
转换回 float
或 double
,你将不得不存储一些东西来跟踪实际是哪种类型。
而不是后者,您可能还想研究使用 std::variant
,它会自动处理存储类型标签,并且还可以帮助自动化大多数类型调度(例如,使用 std::visit
).至少在通常使用的情况下,这将更像是一个实际的标记联合,因此它存储实际值,而不是指向存储在其他地方的值的指针。
我正在尝试将 void 指针转换为动态类型。
例如,我将 double 变量传递给 test1
函数,我希望 sum 函数可以工作。但是我在 sum(*reinterpret_cast<myType*>(tmp))
上收到 C2664 无法转换参数错误。
如果我使用它,它将起作用。
double c= *reinterpret_cast<double*>(tmp);
sum(c);
我该如何解决这个问题?
void sum(double a)
{
cout << "sum:" << a+10 << endl;
}
void test1(void* tmp)
{
typedef decltype(tmp) myType;
sum(*reinterpret_cast<myType*>(tmp));
}
int main()
{
double a = 87.7;
test1(&a);
return 0;
}
首先,动态类型只有在使用继承时才真正有意义。例如,如果您有这样的代码:
class Base {};
class Derived : public Base {};
int main() {
Base *b = new Derived;
}
在这种情况下,b
的静态类型为 Base *
,但动态类型为 Derived *
(因为它被声明为指向 Base
的指针, 但实际上指向 Derived
).
因此,如果您想恢复实际的动态类型,您需要从定义一些基 class 和一些派生 class(es) 开始,并在它们之间进行转换。 When/if 你这样做,你通常想使用 dynamic_cast
而不是 reinterpret_cast
来完成这项工作(它会自动检查实际类型,所以如果你尝试转换,转换将失败到它不是真正指向的类型)。但在大多数情况下,您希望在基 class 中定义某种虚函数,并根据需要在派生 class 中覆盖它,因此您不需要使用 dynamic_cast
根本。另请注意,dynamic_cast
仅适用于包含至少一个虚函数的 classes(但如果您使用 public 继承而没有任何虚函数,则您可能做错了什么) .
或者,您基本上可以创建一个受歧视的联盟。您需要存储一些东西来记录存储的实际类型,并且您将使用它在需要时转换回正确的类型。
enum type { FLOAT, DOUBLE };
struct value {
type t;
void *value;
};
float f = 1.2f
double d = 3.2;
value v { FLOAT, &f };
value y { DOUBLE, &d };
void do_call(value v) {
if (v.type == FLOAT) {
use_float(*reinterpret_cast<float *>(v.value));
else if (v.type == DOUBLE)
use_double(*reinterpret_cast<double *>(v.value));
}
但是,编译器不会在 void *
中存储任何内容来跟踪它真正指向的对象类型。如果你想从 void *
转换回 float
或 double
,你将不得不存储一些东西来跟踪实际是哪种类型。
而不是后者,您可能还想研究使用 std::variant
,它会自动处理存储类型标签,并且还可以帮助自动化大多数类型调度(例如,使用 std::visit
).至少在通常使用的情况下,这将更像是一个实际的标记联合,因此它存储实际值,而不是指向存储在其他地方的值的指针。