目前手上有一个将用 C 实现的科学计算程序重写为 C++实现的任务,需要将其中大量的 C 风格实现改为 OOP 风格实现,但是目前遇到了一些实现上的问题
原始程序中使用struct
维护一个全局计算数据结构,所有的计算 kernel 又会单独使用一系列的struct
来维护每个 kernel 所需要的参数。这些 kernel 参数结构体在用于保存全局计算的结构体中使用了void *
进行管理,然而在迁移到 C++的过程中要求不能使用void *
,故问一问各位大佬如何在 C++中优雅且低成本地实现类似void *
的功能
在原始的程序中,全局计算结构体存在这样的成员
typedef struct {
// ...
void *something[N];
// ...
} GlobalStruct;
其中这个void *
可能对应多个不同的结构体,各个结构体之间相互有不同的成员,例如
typedef struct {
int a;
int b;
short c;
} A;
typedef struct {
int a;
int b;
double d;
} B;
typedef struct {
int a;
int b;
} C;
void kernel_A(A *data);
void kernel_B(B *data);
void kernel_C(C *data);
请问有什么方法可以在 C++程序中实现在上面void *
的效果。
1
exch4nge 2023-07-21 20:27:20 +08:00 via iPhone
一般解法:继承+虚函数,不知道你这个场景能否承担相应开销
|
2
pocarisweat 2023-07-21 20:37:14 +08:00
如果是这些结构体数据成员不同,但要实现相似(但不相同)的行为,可以用继承搭配虚函数。
如果是单纯想把不一样的数据存在一起,可以用 std::variant (C++17). 如果这些数据逻辑上不需要统一管理,放在一起只是为了复用代码,那可以考虑引入模板,然后不同类型各管各的,利用模板复用同一套代码。 |
3
codehz 2023-07-21 20:39:55 +08:00
https://en.cppreference.com/w/cpp/utility/variant
把所有可能的类型都写上去 然后处理函数可以做成重载,或者用 https://en.cppreference.com/w/cpp/utility/variant/visit 里提示的 overloaded 方法 |
4
leonshaw 2023-07-21 20:42:22 +08:00 via Android
有共性就继承,没有就 std::any ,直接用 void* 也没啥不行的。
|
5
favourstreet 2023-07-21 21:40:10 +08:00 via Android
虽然有些离题,不过我想说 C 改 C++我不明白意义何在,直接用 c++写一层接口去调用原来的程序,把 c 的部分包起来不行吗
|
6
shizukupr OP @favourstreet 确实这边有一些私有的东西得依赖一些 C++里面才有的东西,涉及到重写算法逻辑,所以被迫要求完全重构
|
7
ysc3839 2023-07-22 03:11:53 +08:00 via Android
C++没有不能使用 void*一说吧?你这种情况感觉是在自己实现 std::variant ,但又不完全像,或者说是一种自己实现的 RTTI 。std::variant 的基本原理就是用一个变量存储当前类型,然后各种类型都用 union 合在一起。
建议给更多细节,便于判断。 |
8
philon 2023-07-22 17:25:52 +08:00
可能是我没理解你的需求,如果只是单纯想要在 C++中向 C 一样传递任意类型,既然你都定义为指针了,那就只认地址,传参的时候强转为 void*就行了;如果你要利用 C++的特性,那 std::bind+std::function 可能更适合
|
9
iceheart 2023-08-07 07:12:23 +08:00 via Android
抽象类不就是干这个的么
struct Interface { virtual Kernal() = 0; }; |
10
xgdgsc 2023-08-09 21:00:23 +08:00 via Android
如果不是需要在资源受限环境跑的话,科学计算的程序还是 julia 写编译成 c 库调用最优雅
|
11
weeei 2023-09-18 19:39:48 +08:00
OP 的意思应该是:void *something[N]; 这个数组里面存的不同类型的数据,所以原来的写法用了 void * 表示,现在是想设计的优雅一些。这是设计模式的问题了。
解决方法:基本的所有的数据类型都继承一个基类 struct Base {}; C++ 是允许空结构体的,如果子类型没有任何共同点,基类 Base 就定义为空结构体,void *something[N]; 就可以变成 Base *something[N]; 拿到后再根据 sizeof() 确定子类型,或者严谨一点可以给 Base 定义一个 type 字段。 |