求教如何在 C++中优雅地实现在 C 中的 void *所能实现的部分功能 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
shizukupr
V2EX    C++

求教如何在 C++中优雅地实现在 C 中的 void *所能实现的部分功能

  •  
  •   shizukupr 2023-07-21 20:17:56 +08:00 2458 次点击
    这是一个创建于 867 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前手上有一个将用 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 条附言    2023-07-21 21:40:08 +08:00
    上面的实现中不同类所对应的 kernel 内部实现完全不同
    12 条回复    2023-09-18 22:31:43 +08:00
    exch4nge
        1
    exch4nge  
       2023-07-21 20:27:20 +08:00 via iPhone
    一般解法:继承+虚函数,不知道你这个场景能否承担相应开销
    pocarisweat
        2
    pocarisweat  
       2023-07-21 20:37:14 +08:00
    如果是这些结构体数据成员不同,但要实现相似(但不相同)的行为,可以用继承搭配虚函数。

    如果是单纯想把不一样的数据存在一起,可以用 std::variant (C++17).

    如果这些数据逻辑上不需要统一管理,放在一起只是为了复用代码,那可以考虑引入模板,然后不同类型各管各的,利用模板复用同一套代码。
    codehz
        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 方法
    leonshaw
        4
    leonshaw  
       2023-07-21 20:42:22 +08:00 via Android
    有共性就继承,没有就 std::any ,直接用 void* 也没啥不行的。
    favourstreet
        5
    favourstreet  
       2023-07-21 21:40:10 +08:00 via Android
    虽然有些离题,不过我想说 C 改 C++我不明白意义何在,直接用 c++写一层接口去调用原来的程序,把 c 的部分包起来不行吗
    shizukupr
        6
    shizukupr  
    OP
       2023-07-22 00:14:22 +08:00
    @favourstreet 确实这边有一些私有的东西得依赖一些 C++里面才有的东西,涉及到重写算法逻辑,所以被迫要求完全重构
    ysc3839
        7
    ysc3839  
       2023-07-22 03:11:53 +08:00 via Android
    C++没有不能使用 void*一说吧?你这种情况感觉是在自己实现 std::variant ,但又不完全像,或者说是一种自己实现的 RTTI 。std::variant 的基本原理就是用一个变量存储当前类型,然后各种类型都用 union 合在一起。
    建议给更多细节,便于判断。
    philon
        8
    philon  
       2023-07-22 17:25:52 +08:00
    可能是我没理解你的需求,如果只是单纯想要在 C++中向 C 一样传递任意类型,既然你都定义为指针了,那就只认地址,传参的时候强转为 void*就行了;如果你要利用 C++的特性,那 std::bind+std::function 可能更适合
    iceheart
        9
    iceheart  
       2023-08-07 07:12:23 +08:00 via Android
    抽象类不就是干这个的么
    struct Interface {
    virtual Kernal() = 0;
    };
    xgdgsc
        10
    xgdgsc  
       2023-08-09 21:00:23 +08:00 via Android
    如果不是需要在资源受限环境跑的话,科学计算的程序还是 julia 写编译成 c 库调用最优雅
    weeei
        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 字段。
    weeei
        12
    weeei  
       2023-09-18 22:31:43 +08:00
    @weeei sizeof 是操作符,编译期间就确定结果了。应该使用 typeid(*p).name() 判断名称,才能在运行期间确定子类型。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2419 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 15:45 PVG 23:45 LAX 07:45 JFK 10:45
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86